hatebu_entry 0.0.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.
- 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メソッドが最強な件につ..."}]);
|