hatenadiary 0.0.4
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.
- data/ChangeLog +26 -0
- data/LICENSE +28 -0
- data/README +25 -0
- data/lib/hatenadiary.rb +191 -0
- data/test/test_hatenadiary.rb +238 -0
- metadata +87 -0
data/ChangeLog
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
2009-12-04 arikui <arikui.ruby@gmail.com>
|
2
|
+
|
3
|
+
* Rakefile: define common settings as constant.
|
4
|
+
include gemspec.
|
5
|
+
(task 'gemspec') added. this task updates `hatenadiary.gemspec' along to spec written in Rakefile.
|
6
|
+
It means, don't have to correct `hatenadiary.gemspec' by hand.
|
7
|
+
|
8
|
+
* hatenadiary.gemspec: version up to 0.0.4
|
9
|
+
|
10
|
+
2009-11-29 arikui <arikui.ruby@gmail.com>
|
11
|
+
|
12
|
+
* test/test_hatenadiary.rb: replace test by mocha used version.
|
13
|
+
|
14
|
+
* lib/hatenadiary.rb: use hpricot -> nokogiri 1.3.3
|
15
|
+
respond to hatena group diary.
|
16
|
+
(HatenaDiary::Client#post) change interface.
|
17
|
+
(HatenaDiary::Client#initialize): interface extended for test.
|
18
|
+
|
19
|
+
2009-07-03 arikui <arikui.ruby@gmail.com>
|
20
|
+
|
21
|
+
* lib/hatenadiary.rb: use nokogiri -> hpricot
|
22
|
+
|
23
|
+
2009-06-22 arikui <arikui.ruby@gmail.com>
|
24
|
+
|
25
|
+
* lib/hatenadiary.rb: first version.
|
26
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Copyright (c) 2009 arikui <arikui.ruby@gmail.com>
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are
|
6
|
+
met:
|
7
|
+
|
8
|
+
* Redistributions of source code must retain the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer.
|
10
|
+
* Redistributions in binary form must reproduce the above
|
11
|
+
copyright notice, this list of conditions and the following
|
12
|
+
disclaimer in the documentation and/or other materials provided
|
13
|
+
with the distribution.
|
14
|
+
* Neither the name of the arikui-hatenadiary nor the names of its
|
15
|
+
contributors may be used to endorse or promote products derived
|
16
|
+
from this software without specific prior written permission.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
20
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
21
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
22
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
23
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
24
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
26
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
= hatenadiary
|
2
|
+
|
3
|
+
It is a library provides
|
4
|
+
a client for Hatena Diary to post and delete blog entries.
|
5
|
+
|
6
|
+
Developed on:
|
7
|
+
- ruby 1.9.1p243 (2009-07-16 revision 24175) [i386-mswin32]
|
8
|
+
- ruby 1.8.7 (2009-06-12 patchlevel 174) [i386-mswin32]
|
9
|
+
|
10
|
+
- Gem mechanize 0.9.3
|
11
|
+
- Gem nokogiri 1.3.3
|
12
|
+
|
13
|
+
This list means these environments are enable to make all of /test pass.
|
14
|
+
|
15
|
+
|
16
|
+
== Dependences
|
17
|
+
|
18
|
+
- www/mechanize
|
19
|
+
- nokogiri
|
20
|
+
|
21
|
+
|
22
|
+
== Signature
|
23
|
+
|
24
|
+
arikui (arikui.ruby@gmail.com)
|
25
|
+
|
data/lib/hatenadiary.rb
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
#
|
2
|
+
# Distributes under The modified BSD license.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2009 arikui <http://d.hatena.ne.jp/arikui1911/>
|
5
|
+
# All rights reserved.
|
6
|
+
#
|
7
|
+
|
8
|
+
require 'rubygems'
|
9
|
+
|
10
|
+
# Gem Version
|
11
|
+
gem 'nokogiri', '1.3.3'
|
12
|
+
|
13
|
+
require 'nokogiri'
|
14
|
+
require 'mechanize'
|
15
|
+
|
16
|
+
# depend on Ruby version
|
17
|
+
module HatenaDiary
|
18
|
+
module Util
|
19
|
+
if RUBY_VERSION >= '1.9'
|
20
|
+
def encode_to_utf8(str)
|
21
|
+
str.encode(Encoding::UTF_8)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
require 'kconv'
|
25
|
+
|
26
|
+
def encode_to_utf8(str)
|
27
|
+
Kconv.toutf8(str)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module_function :encode_to_utf8
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
module HatenaDiary
|
37
|
+
#
|
38
|
+
# Allocates Client object and makes it login, execute a received block,
|
39
|
+
# and then logout.
|
40
|
+
#
|
41
|
+
# :call-seq:
|
42
|
+
# login(username, password, proxy = nil){|client| ... }
|
43
|
+
#
|
44
|
+
def login(*args, &block)
|
45
|
+
Client.login(*args, &block)
|
46
|
+
end
|
47
|
+
module_function :login
|
48
|
+
|
49
|
+
class LoginError < RuntimeError
|
50
|
+
def set_account(username, password)
|
51
|
+
@username = username
|
52
|
+
@password = password
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
attr_reader :username
|
57
|
+
attr_reader :password
|
58
|
+
end
|
59
|
+
|
60
|
+
class Client
|
61
|
+
def self.mechanizer
|
62
|
+
@mechanizer ||= WWW::Mechanize
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.mechanizer=(klass)
|
66
|
+
@mechanizer = klass
|
67
|
+
end
|
68
|
+
|
69
|
+
# Allocates Client object.
|
70
|
+
#
|
71
|
+
# If block given, login and execute a received block, and then logout ensurely.
|
72
|
+
#
|
73
|
+
# [username] Hatena ID
|
74
|
+
# [password] Password for _username_
|
75
|
+
# [proxy] Proxy configuration; [proxy_url, port_no] | nil
|
76
|
+
#
|
77
|
+
def self.login(username, password, proxy = nil, &block)
|
78
|
+
client = new(username, password)
|
79
|
+
client.set_proxy(*proxy) if proxy
|
80
|
+
return client unless block_given?
|
81
|
+
client.transaction(&block)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Allocates Client object.
|
85
|
+
#
|
86
|
+
# [username] Hatena ID
|
87
|
+
# [password] Password for _username_
|
88
|
+
def initialize(username, password, agent = self.class.mechanizer.new)
|
89
|
+
@agent = agent
|
90
|
+
@username = username
|
91
|
+
@password = password
|
92
|
+
@current_account = nil
|
93
|
+
end
|
94
|
+
|
95
|
+
# Configure proxy.
|
96
|
+
def set_proxy(url, port)
|
97
|
+
@agent.set_proxy(url, port)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Login and execute a received block, and then logout ensurely.
|
101
|
+
def transaction(username = nil, password = nil)
|
102
|
+
raise LocalJumpError, "no block given" unless block_given?
|
103
|
+
login(username, password)
|
104
|
+
begin
|
105
|
+
yield(self)
|
106
|
+
ensure
|
107
|
+
logout
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns a client itself was logined or not.
|
112
|
+
#
|
113
|
+
# -> true | false
|
114
|
+
def login?
|
115
|
+
@current_account ? true : false
|
116
|
+
end
|
117
|
+
|
118
|
+
# Does login.
|
119
|
+
#
|
120
|
+
# If _username_ or _password_ are invalid, raises HatenaDiary::LoginError .
|
121
|
+
def login(username = nil, password = nil)
|
122
|
+
username ||= @username
|
123
|
+
password ||= @password
|
124
|
+
form = @agent.get("https://www.hatena.ne.jp/login").forms.first
|
125
|
+
form["name"] = username
|
126
|
+
form["password"] = password
|
127
|
+
form["persistent"] = "true"
|
128
|
+
response = form.submit
|
129
|
+
@current_account = [username, password]
|
130
|
+
case response.title
|
131
|
+
when "Hatena" then response
|
132
|
+
when "Login - Hatena" then raise LoginError.new("login failure").set_account(username, password)
|
133
|
+
else raise Exception, '[BUG] must not happen (maybe cannot follow hatena spec)'
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Does logout if already logined.
|
138
|
+
def logout
|
139
|
+
return unless login?
|
140
|
+
@agent.get("https://www.hatena.ne.jp/logout")
|
141
|
+
account = @current_account
|
142
|
+
@current_account = nil
|
143
|
+
account
|
144
|
+
end
|
145
|
+
|
146
|
+
# Posts an entry to Hatena diary service.
|
147
|
+
#
|
148
|
+
# Raises HatenaDiary::LoginError unless logined.
|
149
|
+
#
|
150
|
+
# options
|
151
|
+
# [:trivial] check a checkbox of trivial updating.
|
152
|
+
# [:group] assign hatena-group name. edit group diary.
|
153
|
+
#
|
154
|
+
# Invalid options were ignored.
|
155
|
+
def post(yyyy, mm, dd, title, body, options = {})
|
156
|
+
title = Util.encode_to_utf8(title)
|
157
|
+
body = Util.encode_to_utf8(body)
|
158
|
+
form = get_form(yyyy, mm, dd, options[:group]){|r| r.form_with(:name => 'edit') }
|
159
|
+
form["year"] = "%04d" % yyyy
|
160
|
+
form["month"] = "%02d" % mm
|
161
|
+
form["day"] = "%02d" % dd
|
162
|
+
form["title"] = title
|
163
|
+
form["body"] = body
|
164
|
+
form["trivial"] = "true" if options[:trivial]
|
165
|
+
@agent.submit form, form.button_with(:name => 'edit')
|
166
|
+
end
|
167
|
+
|
168
|
+
# Deletes an entry from Hatena diary service.
|
169
|
+
#
|
170
|
+
# Raises HatenaDiary::LoginError unless logined.
|
171
|
+
#
|
172
|
+
# options
|
173
|
+
# [:group] assign hatena-group name. edit group diary.
|
174
|
+
#
|
175
|
+
# Invalid options were ignored.
|
176
|
+
def delete(yyyy, mm, dd, options = {})
|
177
|
+
get_form(yyyy, mm, dd, options[:group]){|r| r.forms.last }.submit
|
178
|
+
end
|
179
|
+
|
180
|
+
private
|
181
|
+
|
182
|
+
def get_form(yyyy, mm, dd, group = nil)
|
183
|
+
raise LoginError, "not login yet" unless login?
|
184
|
+
vals = [group ? "#{group}.g" : "d",
|
185
|
+
@current_account[0],
|
186
|
+
yyyy, mm, dd]
|
187
|
+
yield @agent.get("http://%s.hatena.ne.jp/%s/edit?date=%04d%02d%02d" % vals)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
@@ -0,0 +1,238 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'test/unit'
|
3
|
+
require 'mocha'
|
4
|
+
require 'hatenadiary'
|
5
|
+
|
6
|
+
|
7
|
+
class TestHatenaDiaryAPI < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
@username = 'USERNAME'
|
10
|
+
@password = 'PASSWORD'
|
11
|
+
@proxy_url = "PROXY_URL"
|
12
|
+
@proxy_port = "PROXY_PORT"
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_api_login
|
16
|
+
HatenaDiary::Client.expects(:login)
|
17
|
+
HatenaDiary.login
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_login
|
21
|
+
client = mock()
|
22
|
+
HatenaDiary::Client.expects(:new).with(@username, @password).returns(client)
|
23
|
+
client.expects(:transaction).yields('block delegate check')
|
24
|
+
HatenaDiary::Client.login(@username, @password) do |str|
|
25
|
+
assert_equal 'block delegate check', str
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_login_with_proxy
|
30
|
+
client = mock()
|
31
|
+
HatenaDiary::Client.expects(:new).with(@username, @password).returns(client)
|
32
|
+
client.expects(:set_proxy).with(@proxy_url, @proxy_port)
|
33
|
+
client.expects(:transaction).yields('block delegate check')
|
34
|
+
HatenaDiary::Client.login(@username, @password, [@proxy_url, @proxy_port]) do |str|
|
35
|
+
assert_equal 'block delegate check', str
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_login_without_block
|
40
|
+
client = Object.new
|
41
|
+
HatenaDiary::Client.expects(:new).with(@username, @password).returns(client)
|
42
|
+
assert_equal client, HatenaDiary::Client.login(@username, @password)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_login_without_block_with_proxy
|
46
|
+
client = mock()
|
47
|
+
HatenaDiary::Client.expects(:new).with(@username, @password).returns(client)
|
48
|
+
client.expects(:set_proxy).with(@proxy_url, @proxy_port)
|
49
|
+
assert_equal client, HatenaDiary::Client.login(@username, @password, [@proxy_url, @proxy_port])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
class TestHatenaDiary < Test::Unit::TestCase
|
55
|
+
def setup
|
56
|
+
@username = 'USERNAME'
|
57
|
+
@password = 'PASSWORD'
|
58
|
+
@agent = mock()
|
59
|
+
@client = HatenaDiary::Client.new(@username, @password, @agent)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_set_proxy
|
63
|
+
proxy_url = 'PROXY_URL'
|
64
|
+
proxy_port = 'PROXY_PORT'
|
65
|
+
@agent.expects(:set_proxy).with(proxy_url, proxy_port)
|
66
|
+
@client.set_proxy(proxy_url, proxy_port)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_logout_without_login
|
70
|
+
@client.logout
|
71
|
+
end
|
72
|
+
|
73
|
+
def login_mocking(submit_response_page_title)
|
74
|
+
login_page = mock()
|
75
|
+
form = {}
|
76
|
+
forms = [form]
|
77
|
+
response = mock()
|
78
|
+
@agent.expects(:get).with("https://www.hatena.ne.jp/login").returns(login_page)
|
79
|
+
login_page.expects(:forms).returns(forms)
|
80
|
+
form.expects(:submit).returns(response)
|
81
|
+
response.expects(:title).returns(submit_response_page_title)
|
82
|
+
form
|
83
|
+
end
|
84
|
+
|
85
|
+
def logout_mocking
|
86
|
+
@agent.expects(:get).with("https://www.hatena.ne.jp/logout")
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_login_and_logout
|
90
|
+
# before login
|
91
|
+
assert !@client.login?
|
92
|
+
# login
|
93
|
+
form = login_mocking("Hatena")
|
94
|
+
@client.login
|
95
|
+
assert @client.login?
|
96
|
+
assert_equal form["name"], @username
|
97
|
+
assert_equal form["password"], @password
|
98
|
+
assert_equal form["persistent"], "true"
|
99
|
+
# logout
|
100
|
+
logout_mocking
|
101
|
+
@client.logout
|
102
|
+
assert !@client.login?
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_login_failure
|
106
|
+
login_mocking "Login - Hatena"
|
107
|
+
begin
|
108
|
+
@client.login
|
109
|
+
rescue HatenaDiary::LoginError => ex
|
110
|
+
assert_equal @username, ex.username
|
111
|
+
assert_equal @password, ex.password
|
112
|
+
else
|
113
|
+
flunk "login error must be raised."
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_login_if_hatena_changed
|
118
|
+
login_mocking "*jumbled pagetitle*"
|
119
|
+
begin
|
120
|
+
@client.login
|
121
|
+
rescue Exception => ex
|
122
|
+
assert /must not happen/ =~ ex.message
|
123
|
+
else
|
124
|
+
flunk "exception must be raised"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_transaction
|
129
|
+
assert !@client.login?
|
130
|
+
login_mocking "Hatena"
|
131
|
+
logout_mocking
|
132
|
+
@client.transaction do |client|
|
133
|
+
assert_same @client, client
|
134
|
+
assert @client.login?
|
135
|
+
end
|
136
|
+
assert !@client.login?
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_transaction_without_block
|
140
|
+
assert !@client.login?
|
141
|
+
assert_raises LocalJumpError do
|
142
|
+
@client.transaction
|
143
|
+
end
|
144
|
+
assert !@client.login?
|
145
|
+
end
|
146
|
+
|
147
|
+
def post_mocking(host, date_str)
|
148
|
+
edit_page = mock()
|
149
|
+
form = {}
|
150
|
+
button = Object.new
|
151
|
+
login_mocking "Hatena"
|
152
|
+
logout_mocking
|
153
|
+
@agent.expects(:get).with("http://#{host}.hatena.ne.jp/#{@username}/edit?date=#{date_str}").returns(edit_page)
|
154
|
+
edit_page.expects(:form_with).with(:name => 'edit').returns(form)
|
155
|
+
form.expects(:button_with).with(:name => 'edit').returns(button)
|
156
|
+
@agent.expects(:submit).with(form, button)
|
157
|
+
form
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_post
|
161
|
+
form = post_mocking("d", "12340506")
|
162
|
+
@client.transaction do |client|
|
163
|
+
client.post 1234, 5, 6, 'TITLE', 'BODY'
|
164
|
+
end
|
165
|
+
expected = {
|
166
|
+
"year" => "1234",
|
167
|
+
"month" => "05",
|
168
|
+
"day" => "06",
|
169
|
+
"title" => "TITLE",
|
170
|
+
"body" => "BODY",
|
171
|
+
}
|
172
|
+
assert_equal expected, form
|
173
|
+
assert !form["trivial"]
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_post_trivial
|
177
|
+
form = post_mocking("d", "20071108")
|
178
|
+
@client.transaction do |client|
|
179
|
+
client.post 2007, 11, 8, 'TITLE', 'BODY', :trivial => true
|
180
|
+
end
|
181
|
+
assert_equal "true", form["trivial"]
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_post_group
|
185
|
+
post_mocking "hoge.g", "12340506"
|
186
|
+
@client.transaction do |client|
|
187
|
+
client.post 1234, 5, 6, 'TITLE', 'BODY', :group => 'hoge'
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_post_group_trivial
|
192
|
+
form = post_mocking("hoge.g", "12340506")
|
193
|
+
@client.transaction do |client|
|
194
|
+
client.post 1234, 5, 6, 'TITLE', 'BODY', :group => 'hoge', :trivial => true
|
195
|
+
end
|
196
|
+
assert_equal "true", form["trivial"]
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_post_without_login
|
200
|
+
assert_raises HatenaDiary::LoginError do
|
201
|
+
@client.post 1999, 5, 26, "TITLE", "BODY\n"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def delete_mocking(host, date_str)
|
206
|
+
edit_page = mock()
|
207
|
+
form = {}
|
208
|
+
forms = [form]
|
209
|
+
button = Object.new
|
210
|
+
login_mocking "Hatena"
|
211
|
+
logout_mocking
|
212
|
+
@agent.expects(:get).with("http://#{host}.hatena.ne.jp/#{@username}/edit?date=#{date_str}").returns(edit_page)
|
213
|
+
edit_page.expects(:forms).returns(forms)
|
214
|
+
form.expects(:submit)
|
215
|
+
form
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_delete
|
219
|
+
delete_mocking "d", "12340506"
|
220
|
+
@client.transaction do |client|
|
221
|
+
client.delete 1234, 5, 6
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_delete_group
|
226
|
+
delete_mocking "piyo.g", "12340506"
|
227
|
+
@client.transaction do |client|
|
228
|
+
client.delete 1234, 5, 6, :group => 'piyo'
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_delete_without_login
|
233
|
+
assert_raises HatenaDiary::LoginError do
|
234
|
+
@client.delete 2009, 8, 30
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
metadata
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hatenadiary
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- arikui
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-04 00:00:00 +09:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: mechanize
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: nokogiri
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.3.3
|
34
|
+
version:
|
35
|
+
description: A client for Hatena Diary to post and delete blog entries.
|
36
|
+
email: arikui.ruby@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README
|
43
|
+
- LICENSE
|
44
|
+
- ChangeLog
|
45
|
+
files:
|
46
|
+
- lib/hatenadiary.rb
|
47
|
+
- test/test_hatenadiary.rb
|
48
|
+
- README
|
49
|
+
- LICENSE
|
50
|
+
- ChangeLog
|
51
|
+
has_rdoc: true
|
52
|
+
homepage: http://wiki.github.com/arikui1911/hatenadiary
|
53
|
+
licenses: []
|
54
|
+
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options:
|
57
|
+
- --title
|
58
|
+
- hatenadiary documentation
|
59
|
+
- --opname
|
60
|
+
- index.html
|
61
|
+
- --line-numbers
|
62
|
+
- --main
|
63
|
+
- README
|
64
|
+
- --inline-source
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project: hatenadiary
|
82
|
+
rubygems_version: 1.3.5
|
83
|
+
signing_key:
|
84
|
+
specification_version: 3
|
85
|
+
summary: It is a library provides a client for Hatena Diary to post and delete blog entries.
|
86
|
+
test_files:
|
87
|
+
- test/test_hatenadiary.rb
|