hatenabm 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. data/ChangeLog +6 -0
  2. data/README +53 -0
  3. data/lib/hatenabm.rb +160 -0
  4. data/test/test_hatenabm.rb +75 -0
  5. metadata +44 -0
data/ChangeLog ADDED
@@ -0,0 +1,6 @@
1
+ = HatenaBM Changelog
2
+
3
+ == Version 0.1.0
4
+ initial release
5
+
6
+ * initial release
data/README ADDED
@@ -0,0 +1,53 @@
1
+ = HatenaBM
2
+
3
+ HatenaBM is Hatena Bookmark (Japanese Social Bookmark Service) binding for Ruby.
4
+
5
+ Hatena Bookmark : http://b.hatena.ne.jp
6
+ Hatena Bookmark API Reference (Japanese) : http://d.hatena.ne.jp/keyword/%A4%CF%A4%C6%A4%CA%A5%D6%A5%C3%A5%AF%A5%DE%A1%BC%A5%AFAtomAPI
7
+
8
+ == Installation
9
+
10
+ $ sudo gem install hatenabm
11
+
12
+ == Usage
13
+
14
+ require 'rubygems'
15
+ require 'hatenabm'
16
+ require 'pp'
17
+
18
+ # initialize
19
+ hbm = HatenaBM.new(
20
+ :user => "username",
21
+ :pass => "password"
22
+ )
23
+
24
+ # post new bookmark
25
+ hbm.post(
26
+ :title => "bookmark's title", # title
27
+ :link => "http://www.example.com", # url
28
+ :tags => "foo bar", # tags (separate space)
29
+ :summary => "this is example post." # description of this bookmark
30
+ )
31
+
32
+ # show recent bookmarks (Atom Format)
33
+ pp hbm.recent
34
+
35
+ # show specified bookmark
36
+ pp hbm.get(:eid => "4211817") # eid - bookmark's id
37
+
38
+ # modify posted bookmark
39
+ hbm.modify(
40
+ :eid => "421817", # eid
41
+ :tags => "bar com", # tags (separate space)
42
+ :summary => "modify bookmark's description"
43
+ )
44
+
45
+ # delete specified bookmark
46
+ hbm.delete(:eid => "421817") # eid
47
+
48
+ == Author
49
+ - drawnboy ( http://d.hatena.ne.jp/drawnboy ) <drawn.boy@gmail.com.nospam>
50
+ - s-tanaka ( http://d.hatena.ne.jp/ha-tan )is written by get_wsse method
51
+ - gorou ( http://rails2u.com )
52
+
53
+ License:: 2-clause BSD Lisence
data/lib/hatenabm.rb ADDED
@@ -0,0 +1,160 @@
1
+ require 'net/http'
2
+ require 'time'
3
+ require 'digest/sha1'
4
+ require 'base64'
5
+
6
+ # if using ruby 1.9.0 earlier, define HTTP DELETE Method
7
+ if RUBY_VERSION < '1.9.0'
8
+ module Net
9
+ class HTTP
10
+ class Delete < HTTPRequest
11
+ METHOD = 'DELETE'
12
+ REQUEST_HAS_BODY = false
13
+ RESPONSE_HAS_BODY = true
14
+ end
15
+ def delete(path,initheader = nil)
16
+ res = request(Delete.new(path,initheader))
17
+ res.value unless @newimpl
18
+ res
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ class HatenaBM
25
+
26
+ VERSION = "0.0.3"
27
+
28
+ HATENA_URL = "b.hatena.ne.jp"
29
+ FEED_PATH = "/atom/feed"
30
+ POST_PATH = "/atom/post"
31
+ EDIT_PATH = "/atom/edit/"
32
+
33
+ def initialize(options)
34
+ user = options[:user]
35
+ pass = options[:pass]
36
+ @wsse = get_wsse(user, pass)
37
+ end
38
+
39
+ # Post new bookmark
40
+ # args: title, link, summary, tags
41
+ def post(options)
42
+ title = options[:title]
43
+ link = options[:link]
44
+ summary = options[:summary] || nil
45
+ tags = options[:tags] || nil
46
+ header = {
47
+ "Content-Type" => 'application/x.atom+xml; charset="utf-8"',
48
+ "X-WSSE" => @wsse
49
+ }
50
+ tags = "[#{tags.split(/\s/).join('][')}]" unless tags.nil?
51
+
52
+ data =<<-EOF
53
+ <?xml version="1.0"?>
54
+ <entry xmlns="http://purl.org/atom/ns#">
55
+ <title>#{title}</title>
56
+ <link rel="related" type="text/html" href="#{link}" />
57
+ <summary type="text/plain">#{tags}#{summary}</summary>
58
+ </entry>
59
+ EOF
60
+
61
+ Net::HTTP.version_1_2
62
+ Net::HTTP.start(HATENA_URL){|http|
63
+ response = http.post(POST_PATH, toutf8(data), header)
64
+ raise "Post Error : #{response.code} - #{response.message}" unless response.code == "201"
65
+ return true
66
+ }
67
+ end
68
+
69
+ # Get recent bookmarks
70
+ def recent
71
+ header = { "X-WSSE" => @wsse }
72
+ Net::HTTP.version_1_2
73
+ Net::HTTP.start(HATENA_URL){|http|
74
+ response = http.get(FEED_PATH, header)
75
+ return response.body
76
+ }
77
+ end
78
+
79
+ # Get specified bookmark
80
+ # args : eid
81
+ def get(options)
82
+ eid = options[:eid] || nil
83
+ raise "Get Error : Invalid eid" if eid.nil?
84
+ api_path = EDIT_PATH + eid
85
+ header = { "X-WSSE"=> @wsse }
86
+
87
+ Net::HTTP.version_1_2
88
+ Net::HTTP.start(HATENA_URL){|http|
89
+ response = http.get(api_path, header)
90
+ return response.body
91
+ }
92
+ end
93
+
94
+ # Modify specified bookmark
95
+ # args: eid, title, tags
96
+ def modify(options)
97
+ eid = options[:eid] || nil
98
+ title = options[:title] || nil
99
+ tags = options[:tags] || nil
100
+ summary = options[:summary] || nil
101
+
102
+ raise "Edit Error : need eid" if eid.nil?
103
+
104
+ api_path = EDIT_PATH + eid
105
+ header = { "X-WSSE" => @wsse }
106
+ tags = "[#{tags.split(/\s/).join('][')}]" unless tags.nil?
107
+
108
+ data = "<?xml version=\"1.0\"?>"
109
+ data << "<entry xmlns=\"http://purl.org/atom/ns#\">"
110
+ data << "<title>#{title}</title>" unless title.nil?
111
+ data << "<summary type=\"text/plain\">#{tags}#{summary}</summary>" unless summary.nil?
112
+ data << "</entry>"
113
+
114
+ Net::HTTP.version_1_2
115
+ Net::HTTP.start(HATENA_URL){|http|
116
+ response = http.put(api_path, toutf8(data), header)
117
+ raise "Edit Error : #{response.code} - #{response.message}" unless response.code == "200"
118
+ return true
119
+ }
120
+
121
+ end
122
+
123
+ # Delete specified bookmark
124
+ # args: eid
125
+ def delete(options)
126
+ eid = options[:eid] || nil
127
+ raise "Delete Error : Invalid eid" if eid.nil?
128
+ api_path = EDIT_PATH + eid
129
+ header = { "X-WSSE" => @wsse }
130
+
131
+ Net::HTTP.version_1_2
132
+ Net::HTTP.start(HATENA_URL){|http|
133
+ response = http.delete(api_path, header)
134
+ raise "Delete Error : #{response.code} - #{response.message}" unless response.code == "200"
135
+ return true
136
+ }
137
+ end
138
+
139
+ # Calculate WSSE Header method
140
+ private
141
+ def get_wsse(user, pass)
142
+ created = Time.now.iso8601
143
+
144
+ nonce = ''
145
+ 20.times do
146
+ nonce << rand(256).chr
147
+ end
148
+
149
+ passdigest = Digest::SHA1.digest(nonce + created + pass)
150
+
151
+ return "UsernameToken Username=\"#{user}\", " +
152
+ "PasswordDigest=\"#{Base64.encode64(passdigest).chomp}\", " +
153
+ "Nonce=\"#{Base64.encode64(nonce).chomp}\", " +
154
+ "Created=\"#{created}\""
155
+ end
156
+
157
+ def toutf8(str)
158
+ Kconv.toutf8(str)
159
+ end
160
+ end
@@ -0,0 +1,75 @@
1
+ require 'test/unit'
2
+ require 'hatenabm'
3
+
4
+ class TestHatenaBM < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @hatenabm = HatenaBM.new(:user => "username", :pass => "password")
8
+ end
9
+
10
+ def test_recent
11
+ assert_match(
12
+ /^<\?xml version=\"1\.0\" encoding=\"utf\-8\"\?>/,
13
+ @hatenabm.recent
14
+ )
15
+ end
16
+
17
+ def test_post
18
+ assert_equal(
19
+ true,
20
+ @hatenabm.post(
21
+ :title => "bookmark's title",
22
+ :link => "http://www.example.com",
23
+ :tags => "foo bar",
24
+ :summary => "this is example post."
25
+ )
26
+ )
27
+ end
28
+
29
+ def test_get
30
+ assert_match(
31
+ /^<\?xml version=\"1\.0\" encoding=\"utf\-8\"\?>/,
32
+ @hatenabm.get(:eid => "4211817")
33
+ )
34
+ end
35
+
36
+ def test_modify
37
+ assert(
38
+ true,
39
+ @hatenabm.modify(
40
+ :eid => "421817",
41
+ :tags => "bar com",
42
+ :summary => "modify bookmark's description"
43
+ )
44
+ )
45
+ end
46
+
47
+ def test_delete
48
+ assert(
49
+ true,
50
+ @hatenabm.delete(:eid => "421817")
51
+ )
52
+ end
53
+
54
+ def test_invalid_access
55
+ assert_raises(RuntimeError) do
56
+ @hatenabm.post(:title => "invalid", :summary => "summary")
57
+ end
58
+
59
+ assert_raises(RuntimeError) do
60
+ @hatenabm.get(:invalide => "421817")
61
+ end
62
+
63
+ assert_raises(RuntimeError) do
64
+ @hatenabm.modify(:summary => "summary")
65
+ end
66
+
67
+ assert_raises(RuntimeError) do
68
+ @hatenabm.delete(:invalid => "421817")
69
+ end
70
+
71
+ assert_raises(RuntimeError) do
72
+ @hatenabm.delete(:eid => "invalid")
73
+ end
74
+ end
75
+ end
metadata ADDED
@@ -0,0 +1,44 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.10
3
+ specification_version: 1
4
+ name: hatenabm
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.0
7
+ date: 2005-10-14
8
+ summary: Hatena Bookmark AtomAPI binding for Ruby
9
+ require_paths:
10
+ - lib
11
+ email: drawn.boy@gmail.com.nospam
12
+ homepage: http://hatenabm.rubyforge.org
13
+ rubyforge_project:
14
+ description:
15
+ autorequire: cool
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ -
22
+ - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ platform: ruby
27
+ authors:
28
+ - drawnboy
29
+ files:
30
+ - test/test_hatenabm.rb
31
+ - lib/hatenabm.rb
32
+ - README
33
+ - ChangeLog
34
+ test_files:
35
+ - test/test_hatenabm.rb
36
+ rdoc_options:
37
+ - "--main"
38
+ - README
39
+ extra_rdoc_files:
40
+ - README
41
+ executables: []
42
+ extensions: []
43
+ requirements: []
44
+ dependencies: []