hatebu_entry 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +6 -0
- data/bin/hatebu_entry +5 -0
- data/hatebu_entry.gemspec +28 -0
- data/lib/hatebu_entry/command.rb +47 -0
- data/lib/hatebu_entry/version.rb +3 -0
- data/lib/hatebu_entry.rb +144 -0
- data/sample/sample.rb +29 -0
- data/spec/hatebu_entry_spec.rb +149 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/hatebu_entry.jsonp +1 -0
- data/spec/support/hatebu_entry0.html +821 -0
- data/spec/support/hatebu_entry1.html +818 -0
- data/spec/support/hatebu_entry2.html +817 -0
- data/spec/support/no_entry.jsonp +1 -0
- metadata +158 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0aab4957200e35089c390385b7783515754062e9
|
4
|
+
data.tar.gz: 34e4799ece62fabbfecaa37c488ed7a53a6b383d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7a780f297fd288a18adfecbdf8fc17acd19c6f012fe129d15154229094468bb443ef1e77ac9a8ec608b0e17634a6e8cfbaa10590abfb96456eef27408cd78be5
|
7
|
+
data.tar.gz: 06a8e2c519b77497d4c88a48904670bef01b5bee8fed6ca31cd5548c0ac00ae2d581a313d190af8684e4a5ae0f082db4198781beb9ab0830a2c4b9902da5871b
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 kyoendo
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# HatebuEntry
|
2
|
+
|
3
|
+
HatebuEntry is a tool for retrieving and handling Hatena Bookmark entry lists written in Ruby.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'hatebu_entry'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install hatebu_entry
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Try this;
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require 'hatebu_entry'
|
25
|
+
|
26
|
+
uri = 'http://d.hatena.ne.jp'
|
27
|
+
hent = HatebuEntry.new(uri)
|
28
|
+
|
29
|
+
puts hent.entries
|
30
|
+
```
|
31
|
+
|
32
|
+
You will get like this.
|
33
|
+
|
34
|
+
6691: 僕は自分が思っていたほどは頭がよくなかった - しのごの... (http://d.hatena.ne.jp/tictac/20120110/p1)
|
35
|
+
5788: 「 2 」か「 9 」で割ってみる - ナイトシフト (http://d.hatena.ne.jp/nightshift/20090121/1232521713)
|
36
|
+
5605: 読みやすい文章を書くための技法 - RyoAnna’s iPhone Blog (http://d.hatena.ne.jp/RyoAnna/20100824/1282660678)
|
37
|
+
4483: この「いじめ対策」はすごい! - 森口朗公式ブログ (http://d.hatena.ne.jp/moriguchiakira/20090520)
|
38
|
+
4167: 知らないと損する英語の速読方法(1) - 一法律学徒の英語... (http://d.hatena.ne.jp/kousuke-i/20081203/1228314824)
|
39
|
+
3973: パワポでもここまでできる!米財務省から学べる美しい資... (http://d.hatena.ne.jp/stj064/20120401/p1)
|
40
|
+
3968: デジタル一眼レフカメラの基礎から実践まで - #RyoAnnaBlog (http://d.hatena.ne.jp/RyoAnna/20120501/1335884196)
|
41
|
+
3853: 『忙しい人』と『仕事ができる人』の20の違い (http://d.hatena.ne.jp/favre21/20070927)
|
42
|
+
3717: MacBook Air 11インチ欲しい!とは - はてなキーワード (http://d.hatena.ne.jp/keyword/MacBook%20Air%2011%A5%A4%A5%F3%A5%C1%CD%DF%A4%B7%A4%A4%A1%AA)
|
43
|
+
3715: おさえておきたいメールで使う敬語 - かみんぐあうとっ (http://d.hatena.ne.jp/komoko-i/20110524/p1)
|
44
|
+
|
45
|
+
|
46
|
+
## Contributing
|
47
|
+
|
48
|
+
1. Fork it
|
49
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
50
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
51
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
52
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/hatebu_entry
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'hatebu_entry/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "hatebu_entry"
|
8
|
+
spec.version = HatebuEntry::VERSION
|
9
|
+
spec.authors = ["kyoendo"]
|
10
|
+
spec.email = ["postagie@gmail.com"]
|
11
|
+
spec.description = %q{HatebuEntry is a tool for retrieving and handling Hatena Bookmark entry lists written in Ruby.}
|
12
|
+
spec.summary = %q{Hatena bookmark entry list handler}
|
13
|
+
spec.homepage = "https://github.com/melborne/hatebu_entry"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.required_ruby_version = '>= 1.9.3'
|
22
|
+
spec.add_runtime_dependency 'nokogiri'
|
23
|
+
spec.add_runtime_dependency 'thor'
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
spec.add_development_dependency "fakeweb", "~> 1.3"
|
28
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
class HatebuEntry::Command < Thor
|
4
|
+
desc "get URL", "Get Hatena bookmark entries for URL"
|
5
|
+
option :pages, aliases:"-p", default:0
|
6
|
+
option :sort, aliases:"-s", default:"count"
|
7
|
+
def get(url)
|
8
|
+
entries = HatebuEntry.new(url, options[:sort])
|
9
|
+
.entries(options[:pages].to_i)
|
10
|
+
pretty_print begin
|
11
|
+
options[:sort]=='count' ? entries.sort_by { |ent| -ent.count } : entries
|
12
|
+
end
|
13
|
+
rescue
|
14
|
+
abort "something go wrong."
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "merge *URLs", "Merge counts for same entries on several URLs"
|
18
|
+
option :pages, aliases:"-p", default:1
|
19
|
+
option :sort, aliases:"-s", default:"count"
|
20
|
+
def merge(*urls)
|
21
|
+
abort "At least 2 urls needed." if urls.size < 2
|
22
|
+
entries = urls.map do |url|
|
23
|
+
HatebuEntry.new(url, options[:sort]).entries options[:pages].to_i
|
24
|
+
end
|
25
|
+
merged = entries.inject {|mem, ent| HatebuEntry::Entry.merge(mem, ent) }
|
26
|
+
pretty_print merged.sort_by { |ent| -ent.count }
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "version", "Show HatebuEntry version"
|
30
|
+
def version
|
31
|
+
puts "HatebuEntry #{HatebuEntry::VERSION} (c) 2013 kyoendo"
|
32
|
+
end
|
33
|
+
map "-v" => :version
|
34
|
+
|
35
|
+
no_commands do
|
36
|
+
def pretty_print(entries)
|
37
|
+
lines = entries.map do |ent|
|
38
|
+
"%5d: %s (%s)" % [ent.count, c(ent.title), ent.link]
|
39
|
+
end
|
40
|
+
puts lines
|
41
|
+
end
|
42
|
+
|
43
|
+
def c(str, n='32')
|
44
|
+
"\e[#{n}m#{str}\e[0m"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/hatebu_entry.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
require "hatebu_entry/version"
|
2
|
+
require 'hatebu_entry/command'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'json'
|
5
|
+
require 'date'
|
6
|
+
require 'cgi'
|
7
|
+
|
8
|
+
require 'nokogiri'
|
9
|
+
|
10
|
+
class HatebuEntry
|
11
|
+
# link: uri string
|
12
|
+
# count: integer
|
13
|
+
# title: string
|
14
|
+
class Entry < Struct.new(:link, :count, :title)
|
15
|
+
alias :url :link
|
16
|
+
alias :bookmarks :count
|
17
|
+
def date
|
18
|
+
@date ||= Date.parse(link)
|
19
|
+
rescue ArgumentError
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
"%5d: %s (%s)" % [count, title, link]
|
25
|
+
end
|
26
|
+
|
27
|
+
# to find same entry but other hosts
|
28
|
+
def homogeneous?(other)
|
29
|
+
return false if self == other
|
30
|
+
return nil if [self, other].any? { |e| e.date.nil? }
|
31
|
+
self.date == other.date &&
|
32
|
+
title_similar?(self.title, other.title)
|
33
|
+
end
|
34
|
+
alias :same? :homogeneous?
|
35
|
+
|
36
|
+
def title_similar?(a, b)
|
37
|
+
a, b = [a, b].map { |str| str.gsub(/\w+/, '')[0..5] }
|
38
|
+
a == b
|
39
|
+
end
|
40
|
+
private :title_similar?
|
41
|
+
|
42
|
+
class MergeError < StandardError; end
|
43
|
+
|
44
|
+
# Merge its count
|
45
|
+
def merge(other)
|
46
|
+
count = self.count + other.count
|
47
|
+
if block_given? && !yield(self, other)
|
48
|
+
raise MergeError, "They can't merge"
|
49
|
+
else
|
50
|
+
Entry.new(self.link, count, self.title)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Merge two entry lists
|
55
|
+
def self.merge(ls_a, ls_b)
|
56
|
+
if [ls_a, ls_b].all? { |ls| ls.is_a? Entry }
|
57
|
+
raise ArgumentError, 'Arguments must be entry objects'
|
58
|
+
end
|
59
|
+
entries = []
|
60
|
+
ls_a.each do |a|
|
61
|
+
if m = ls_b.detect { |b| a.homogeneous? b }
|
62
|
+
entries.push a.merge(m)
|
63
|
+
ls_b.delete(m)
|
64
|
+
else
|
65
|
+
entries.push a
|
66
|
+
end
|
67
|
+
end
|
68
|
+
entries + ls_b
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
attr_accessor :params
|
73
|
+
#sort: count, eid or hot
|
74
|
+
def initialize(site, sort='count')
|
75
|
+
@params = {url: site, sort: sort, of: 0*20}
|
76
|
+
end
|
77
|
+
|
78
|
+
def entries(pages=0)
|
79
|
+
if pages <= 0
|
80
|
+
get_entries(:jsonp) # get 10 entries with jsonp
|
81
|
+
else
|
82
|
+
# get 20 entries per page with html
|
83
|
+
mutex = Mutex.new
|
84
|
+
pages.times.map { |i|
|
85
|
+
Thread.fork(i) do |_i|
|
86
|
+
mutex.synchronize {
|
87
|
+
params.update(of: _i*20)
|
88
|
+
get_entries(:html)
|
89
|
+
}
|
90
|
+
end
|
91
|
+
}.map(&:value).flatten
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_entries(api)
|
96
|
+
entries =
|
97
|
+
case api
|
98
|
+
when :jsonp then parse_jsonp(call_hatena_entry_api :jsonp)
|
99
|
+
when :html then parse_html(call_hatena_entry_api :html)
|
100
|
+
end
|
101
|
+
entries.map { |h| Entry.new h['link'], Integer(h['count']), h['title'] }
|
102
|
+
end
|
103
|
+
|
104
|
+
def call_hatena_entry_api(api)
|
105
|
+
uri = {jsonp: build_uri('/json?'), html: build_uri('?')}[api]
|
106
|
+
get uri
|
107
|
+
end
|
108
|
+
|
109
|
+
def get(uri)
|
110
|
+
open(uri).read
|
111
|
+
rescue => e
|
112
|
+
abort "HTTP Access Error: #{e.response}"
|
113
|
+
end
|
114
|
+
|
115
|
+
HatenaURI = "http://b.hatena.ne.jp/entrylist"
|
116
|
+
|
117
|
+
def build_uri(joint, params=@params)
|
118
|
+
HatenaURI + joint + build_params(params)
|
119
|
+
end
|
120
|
+
|
121
|
+
def build_params(params)
|
122
|
+
params.map { |k, v| "#{h k}=#{h v}" } * '&'
|
123
|
+
end
|
124
|
+
|
125
|
+
def h(str)
|
126
|
+
CGI.escape(str.to_s)
|
127
|
+
end
|
128
|
+
|
129
|
+
def parse_jsonp(jsonp)
|
130
|
+
jsonp.scan(/{.+?}/).map { |data| JSON.parse data }
|
131
|
+
end
|
132
|
+
|
133
|
+
def parse_html(html)
|
134
|
+
entries = []
|
135
|
+
doc = Nokogiri::HTML(html)
|
136
|
+
doc.css('li.entry-unit').each do |ent|
|
137
|
+
count = ent['data-bookmark-count'].to_i
|
138
|
+
a = ent.at('.entry-contents a')
|
139
|
+
title, href = a['title'], a['href']
|
140
|
+
entries << {'link' => href, 'count' => count, 'title' => title}
|
141
|
+
end
|
142
|
+
entries
|
143
|
+
end
|
144
|
+
end
|
data/sample/sample.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'hatebu_entry'
|
2
|
+
|
3
|
+
githubio = 'http://melborne.github.io'
|
4
|
+
githubcom = 'http://melborne.github.com'
|
5
|
+
hatena = 'http://d.hatena.ne.jp/keyesberry'
|
6
|
+
|
7
|
+
def get_entries(url_list, pages=1)
|
8
|
+
url_list.map do |url|
|
9
|
+
puts "Bookmark entries retrieving from #{url}..."
|
10
|
+
HatebuEntry.new(url).entries(pages).tap do |s|
|
11
|
+
puts "#{s.size} entries retrieved."
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
gitio_ent, gitcom_ent, hatena_ent = get_entries([githubio, githubcom, hatena], 5)
|
17
|
+
|
18
|
+
puts "\nMerging entries..."
|
19
|
+
|
20
|
+
entries = HatebuEntry::Entry.merge(gitio_ent, gitcom_ent)
|
21
|
+
entries = HatebuEntry::Entry.merge(entries, hatena_ent)
|
22
|
+
|
23
|
+
puts "\nFollowing is top 20 entries."
|
24
|
+
puts
|
25
|
+
|
26
|
+
puts entries.lazy
|
27
|
+
.sort_by{ |e| -e.count }
|
28
|
+
.map { |h| "%i: %s (%s)" % [h.count, h.title, h.link] }
|
29
|
+
.take(20)
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HatebuEntry do
|
4
|
+
it 'should have a version number' do
|
5
|
+
HatebuEntry::VERSION.should_not be_nil
|
6
|
+
end
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
FakeWeb.clean_registry
|
10
|
+
site = "http://melborne.github.com"
|
11
|
+
@hent = HatebuEntry.new(site)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#build_json_uri' do
|
15
|
+
it 'returns json uri for Hatena bookmark entry' do
|
16
|
+
expected = "http://b.hatena.ne.jp/entrylist/json?" +
|
17
|
+
"url=http%3A%2F%2Fmelborne.github.com&sort=count&of=0"
|
18
|
+
expect(@hent.build_uri '/json?').to eq expected
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#call_hatena_entry_api' do
|
23
|
+
it 'returns jsonp data of Hatena bookmark info' do
|
24
|
+
uri = @hent.build_uri('/json?')
|
25
|
+
mock_hatebu_entry_api(uri)
|
26
|
+
expect(@hent.call_hatena_entry_api :jsonp).to match /^\(\[{"link":.+}\]\);$/
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns empty jsonp data with a no bookmarked site' do
|
30
|
+
site = "http://melborne.github.co.jp"
|
31
|
+
hent = HatebuEntry.new(site)
|
32
|
+
mock_hatebu_entry_api('http://sample.com', 'no_entry.jsonp')
|
33
|
+
expect(hent.call_hatena_entry_api :jsonp).to eq "([]);"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#get_entries' do
|
38
|
+
context 'gets Bookmark entries with jsonp' do
|
39
|
+
it 'returns entries with an array' do
|
40
|
+
uri = @hent.build_uri('/json?')
|
41
|
+
mock_hatebu_entry_api(uri)
|
42
|
+
entries = @hent.get_entries(:jsonp)
|
43
|
+
expect(entries.size).to eq 10
|
44
|
+
expect(entries.first).to be_instance_of(HatebuEntry::Entry)
|
45
|
+
expect(entries.first.count).to eq 1377
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'gets Bookmark entries with html' do
|
50
|
+
it 'returns entries with an array' do
|
51
|
+
uri = @hent.build_uri('?')
|
52
|
+
mock_hatebu_entry_api(uri, 'hatebu_entry0.html')
|
53
|
+
entries = @hent.get_entries(:html)
|
54
|
+
expect(entries.size).to eq 20
|
55
|
+
expect(entries.first).to be_instance_of(HatebuEntry::Entry)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#parse_jsonp' do
|
61
|
+
it 'returns an array of hashes containing entry data' do
|
62
|
+
str = fixture('hatebu_entry.jsonp')
|
63
|
+
entries = @hent.parse_jsonp(str)
|
64
|
+
expect(entries).to be_instance_of(Array)
|
65
|
+
expect(entries.first).to be_instance_of(Hash)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#parse_html' do
|
70
|
+
it 'returns an array of hashes containing entry data' do
|
71
|
+
str = fixture('hatebu_entry0.html')
|
72
|
+
entries = @hent.parse_html(str)
|
73
|
+
expect(entries).to be_instance_of(Array)
|
74
|
+
expect(entries.first).to be_instance_of(Hash)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#entries' do
|
79
|
+
it 'returns entries with jsonp' do
|
80
|
+
uri = @hent.build_uri('/json?')
|
81
|
+
mock_hatebu_entry_api(uri)
|
82
|
+
entries = @hent.entries
|
83
|
+
expect(entries.size).to eq 10
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'get entries with html' do
|
87
|
+
before(:each) do
|
88
|
+
uri = @hent.build_uri('?')
|
89
|
+
3.times do |i|
|
90
|
+
@hent.params.update(of: i*20)
|
91
|
+
mock_hatebu_entry_api(uri, "hatebu_entry#{i}.html")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'returns first 20 entries' do
|
96
|
+
entries = @hent.entries(1)
|
97
|
+
expect(entries.size).to eq 20
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'returns first 60 entries' do
|
101
|
+
entries = @hent.entries(3)
|
102
|
+
expect(entries.size).to eq 60
|
103
|
+
expect(entries.last.title).to match /Graphviz/
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe HatebuEntry::Entry do
|
110
|
+
let(:ent) { HatebuEntry::Entry }
|
111
|
+
before(:each) do
|
112
|
+
@ent1 = ent.new("http://d.hatena.ne.jp/keyesberry/20130304/p1", 20,"知って得する!55のRubyのトリビアな記法")
|
113
|
+
@ent2 = ent.new("http://melborne.github.io/2013/03/04/ruby/", 10,"知って得する!55のRubyのトリビアな記法")
|
114
|
+
@ent3 = ent.new("http://melborne.github.com/2013/03/05/ruby/", 10,"知って得する!55のRubyのトリビアな記法")
|
115
|
+
@ent4 = ent.new("http://melborne.github.com/2013/03/04/ruby/", 10,"55のRubyのトリビアな記法")
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#homogeneous?' do
|
119
|
+
it 'returns true when date and title are same' do
|
120
|
+
expect(@ent1.homogeneous? @ent2).to be_true
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'returns false when title are same but date are not' do
|
124
|
+
expect(@ent1.homogeneous? @ent3).to be_false
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'returns false when date are same but title are not' do
|
128
|
+
expect(@ent1.homogeneous? @ent4).to be_false
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
describe '#merge' do
|
133
|
+
it 'merge others count amount to self count' do
|
134
|
+
merged = @ent1.merge(@ent2)
|
135
|
+
expect(merged.count).to eq 30
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'merge when these are homogeneous' do
|
139
|
+
it 'should success when they are homogeneous' do
|
140
|
+
merged = @ent1.merge(@ent2) { |a, b| a.homogeneous? b }
|
141
|
+
expect(merged.count).to eq 30
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should fail when they are not homogeneous' do
|
145
|
+
expect{ @ent1.merge(@ent3) { |a, b| a.homogeneous? b } }.to raise_error(HatebuEntry::Entry::MergeError)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'hatebu_entry'
|
3
|
+
require 'fakeweb'
|
4
|
+
|
5
|
+
module HelperMethods
|
6
|
+
def fixture(name)
|
7
|
+
File.read("#{__dir__}/support/#{name}")
|
8
|
+
end
|
9
|
+
|
10
|
+
def mock_hatebu_entry_api(uri, fix='hatebu_entry.jsonp')
|
11
|
+
response ||= fixture(fix)
|
12
|
+
FakeWeb.register_uri(:get, uri, :body => response)
|
13
|
+
rescue Errno::ENOENT
|
14
|
+
response = fixture("no_entry.jsonp")
|
15
|
+
retry
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec.configuration.include(HelperMethods)
|
@@ -0,0 +1 @@
|
|
1
|
+
([{"link":"http://melborne.github.com/2012/04/09/to-newbie/","count":"1377","title":"これからRubyを始める人たちへ"},{"link":"http://melborne.github.com/2013/03/04/ruby-trivias-you-should-know-4/","count":"633","title":"知って得する!55のRubyのトリビアな記法"},{"link":"http://melborne.github.com/2013/02/25/i-wanna-say-something-about-rubys-case/","count":"514","title":"Rubyのcaseを〇〇(言語名)のswitch文だと思っている人たちにぼ..."},{"link":"http://melborne.github.com/2011/06/22/21-Ruby-21-Trivia-Notations-you-should-know-in-Ruby/","count":"442","title":"知って得する21のRubyのトリビアな記法"},{"link":"http://melborne.github.com/2012/09/09/understand-js-oop-with-ruby-brain/","count":"435","title":"Ruby脳が理解するJavaScriptのオブジェクト指向"},{"link":"http://melborne.github.com/2012/12/25/ebooks-for-learning-ruby/","count":"269","title":"今年の冬休みに電子書籍であなたがRubyを習得しなければい..."},{"link":"http://melborne.github.com/2012/07/16/ruby-methods-analysis/","count":"236","title":"Ruby、君のオブジェクトはなんて呼び出せばいいの?"},{"link":"http://melborne.github.com/2013/01/21/why-fp-with-ruby/","count":"187","title":"Rubyを使って「なぜ関数プログラミングは重要か」を読み解..."},{"link":"http://melborne.github.com/2012/09/15/understand-js-oop-with-ruby-brain-2/","count":"178","title":"Ruby脳が理解するJavaScriptのオブジェクト指向(その2)"},{"link":"http://melborne.github.com/2013/01/24/csv-table-method-is-awesome/","count":"145","title":"Ruby標準添付ライブラリcsvのCSV.tableメソッドが最強な件につ..."}]);
|