hatenablog 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1784b95efbc79289c1fcaefa30ae898223454a17
4
- data.tar.gz: 0a57f752ea79980d82cd6fd4d11f020cabcfed24
3
+ metadata.gz: 6c7e933e59b738cfcda010915591ffe89e236651
4
+ data.tar.gz: 0947478b9a9a5e8d706f6d196d4755bbfd6988d3
5
5
  SHA512:
6
- metadata.gz: 7a7e3181855b17a2aa47863c0279eb661f816bc242e90426feb3a67fde522d35c6c8674005be320e4932e1d7230a83255f79de0b899c9204196e9091e9b7d012
7
- data.tar.gz: d2e5ba03fb472e2e2bae2628c9ea46f0c9a805105849ca10b2d56911235859fd829d1e0940feedf5203c8c86ae6a8760ab75c1878d020ee8cf82fc608705dc6b
6
+ metadata.gz: a7715ef9b24771c3a73d4be1d93e9f8e873d909b0aa92442d7bbe4e706202c8b423287bbe479ba6ba899626f9fd75e11937a5c3ce33b1784bbd41a743ed7ad60
7
+ data.tar.gz: df97bcf0b81ec75e4ab068d09ce597eb273fa780f60fbbf1ee82568b4ae087c144a3c8a30024ba548b6b219a92edfc6dda365b71e2917a28f7906b0954ddbd2d
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![Test Coverage](https://codeclimate.com/github/kymmt90/hatenablog/badges/coverage.svg)](https://codeclimate.com/github/kymmt90/hatenablog/coverage)
6
6
 
7
7
  A library for Hatenablog AtomPub API.
8
- This gem supports following operations using OAuth authorization:
8
+ This gem supports following operations using OAuth or Basic authorization:
9
9
 
10
10
  - Get blog feeds, entries and categories
11
11
  - Post blog entries
@@ -70,12 +70,23 @@ user_id: <%= ENV['USER_ID'] %>
70
70
  blog_id: <%= ENV['BLOG_ID'] %>
71
71
  ```
72
72
 
73
+ ### (OPTIONAL) Get Basic Authentication credentials
74
+ If you want to use Basic Authentication, visit `http://blog.hatena.ne.jp/#{user_id}/#{blog_id}/config/detail`
75
+ and check your API key (APIキー) and set up `config.yml` like the following.
76
+
77
+ ```yml
78
+ auth_type: basic
79
+ api_key: <%= ENV['API_KEY'] %>
80
+ user_id: <%= ENV['USER_ID'] %>
81
+ blog_id: <%= ENV['BLOG_ID'] %>
82
+ ```
83
+
73
84
  ## Usage
74
85
 
75
86
  ```ruby
76
87
  require 'hatenablog'
77
88
 
78
- # Read the OAuth configuration from 'config.yml'
89
+ # Read the configuration from 'config.yml'
79
90
  Hatenablog::Client.create do |blog|
80
91
  # Get each entry's content
81
92
  blog.entries.each do |entry|
@@ -1,9 +1,8 @@
1
- require 'oauth'
2
-
3
1
  require 'hatenablog/category'
4
2
  require 'hatenablog/entry'
5
3
  require 'hatenablog/feed'
6
4
  require 'hatenablog/configuration'
5
+ require 'hatenablog/requester'
7
6
 
8
7
  module Hatenablog
9
8
  class Client
@@ -13,16 +12,14 @@ module Hatenablog
13
12
  MEMBER_URI = "https://blog.hatena.ne.jp/%s/%s/atom/entry/%s".freeze
14
13
  CATEGORY_URI = "https://blog.hatena.ne.jp/%s/%s/atom/category".freeze
15
14
 
16
- attr_writer :access_token
15
+ attr_writer :requester
17
16
 
18
17
  # Create a new hatenablog AtomPub client from a configuration file.
19
18
  # @param [String] config_file configuration file path
20
19
  # @return [Hatenablog::Client] created hatenablog client
21
20
  def self.create(config_file = DEFAULT_CONFIG_PATH)
22
- config = Configuration.new(config_file)
23
- blog = Hatenablog::Client.new(config.consumer_key, config.consumer_secret,
24
- config.access_token, config.access_token_secret,
25
- config.user_id, config.blog_id)
21
+ config = Configuration.create(config_file)
22
+ blog = Hatenablog::Client.new(config)
26
23
  return blog unless block_given?
27
24
  yield blog
28
25
  end
@@ -172,20 +169,14 @@ module Hatenablog
172
169
 
173
170
  private
174
171
 
175
- def initialize(consumer_key, consumer_secret, access_token, access_token_secret,
176
- user_id, blog_id)
177
- consumer = OAuth::Consumer.new(consumer_key, consumer_secret)
178
- @access_token = OAuthAccessToken.new(OAuth::AccessToken.new(consumer,
179
- access_token,
180
- access_token_secret))
181
-
182
- @user_id = user_id
183
- @blog_id = blog_id
172
+ def initialize(config)
173
+ @requester = Requester.create(config)
174
+ @user_id = config.user_id
175
+ @blog_id = config.blog_id
184
176
  end
185
177
 
186
-
187
178
  def get(uri)
188
- @access_token.get(uri)
179
+ @requester.get(uri)
189
180
  end
190
181
 
191
182
  def get_collection(uri = collection_uri)
@@ -200,84 +191,15 @@ module Hatenablog
200
191
  end
201
192
 
202
193
  def post(entry_xml, uri = collection_uri)
203
- @access_token.post(uri, entry_xml)
194
+ @requester.post(uri, entry_xml)
204
195
  end
205
196
 
206
197
  def put(entry_xml, uri)
207
- @access_token.put(uri, entry_xml)
198
+ @requester.put(uri, entry_xml)
208
199
  end
209
200
 
210
201
  def delete(uri)
211
- @access_token.delete(uri)
202
+ @requester.delete(uri)
212
203
  end
213
204
  end
214
-
215
- class OAuthAccessToken
216
-
217
- # Create a new OAuth 1.0a access token.
218
- # @param [OAuth::AccessToken] access_token access token object
219
- def initialize(access_token)
220
- @access_token = access_token
221
- end
222
-
223
- # HTTP GET method
224
- # @param [string] uri target URI
225
- # @return [Net::HTTPResponse] HTTP response
226
- def get(uri)
227
- begin
228
- response = @access_token.get(uri)
229
- rescue => problem
230
- raise OAuthError, 'Fail to GET: ' + problem.to_s
231
- end
232
- response
233
- end
234
-
235
- # HTTP POST method
236
- # @param [string] uri target URI
237
- # @param [string] body HTTP request body
238
- # @param [string] headers HTTP request headers
239
- # @return [Net::HTTPResponse] HTTP response
240
- def post(uri,
241
- body = '',
242
- headers = { 'Content-Type' => 'application/atom+xml; type=entry' } )
243
- begin
244
- response = @access_token.post(uri, body, headers)
245
- rescue => problem
246
- raise OAuthError, 'Fail to POST: ' + problem.to_s
247
- end
248
- response
249
- end
250
-
251
- # HTTP PUT method
252
- # @param [string] uri target URI
253
- # @param [string] body HTTP request body
254
- # @param [string] headers HTTP request headers
255
- # @return [Net::HTTPResponse] HTTP response
256
- def put(uri,
257
- body = '',
258
- headers = { 'Content-Type' => 'application/atom+xml; type=entry' } )
259
- begin
260
- response = @access_token.put(uri, body, headers)
261
- rescue => problem
262
- raise OAuthError, 'Fail to PUT: ' + problem.to_s
263
- end
264
- response
265
- end
266
-
267
- # HTTP DELETE method
268
- # @param [string] uri target URI
269
- # @param [string] headers HTTP request headers
270
- # @return [Net::HTTPResponse] HTTP response
271
- def delete(uri,
272
- headers = { 'Content-Type' => 'application/atom+xml; type=entry' })
273
- begin
274
- response = @access_token.delete(uri, headers)
275
- rescue => problem
276
- raise OAuthError, 'Fail to DELETE: ' + problem.to_s
277
- end
278
- response
279
- end
280
- end
281
-
282
- class OAuthError < StandardError; end
283
205
  end
@@ -1,30 +1,23 @@
1
1
  require 'erb'
2
2
  require 'yaml'
3
+ require 'ostruct'
3
4
 
4
5
  module Hatenablog
5
- class Configuration
6
- # For OAuth authorization.
7
- attr_reader :consumer_key, :consumer_secret, :access_token, :access_token_secret
8
-
9
- attr_reader :user_id, :blog_id
6
+ class Configuration < OpenStruct
7
+ OAUTH_KEYS = %w(consumer_key consumer_secret access_token access_token_secret user_id blog_id)
8
+ BASIC_KEYS = %w(api_key user_id blog_id)
10
9
 
11
10
  # Create a new configuration.
12
11
  # @param [String] config_file configuration file path
13
12
  # @return [Hatenablog::Configuration]
14
- def initialize(config_file)
13
+ def self.create(config_file)
15
14
  config = YAML.load(ERB.new(File.read(config_file)).result)
16
- unless config.has_key?('consumer_key') && config.has_key?('consumer_secret') &&
17
- config.has_key?('access_token') && config.has_key?('access_token_secret') &&
18
- config.has_key?('user_id') && config.has_key?('blog_id')
19
- raise ConfigurationError, 'the configure file is incorrect'
15
+ keys = config['auth_type'] == 'basic' ? BASIC_KEYS : OAUTH_KEYS
16
+ unless (lacking_keys = keys.select {|key| !config.has_key? key}).empty?
17
+ raise ConfigurationError, "Following keys are not setup. #{lacking_keys}"
20
18
  end
21
19
 
22
- @consumer_key = config['consumer_key']
23
- @consumer_secret = config['consumer_secret']
24
- @access_token = config['access_token']
25
- @access_token_secret = config['access_token_secret']
26
- @user_id = config['user_id']
27
- @blog_id = config['blog_id']
20
+ new(config)
28
21
  end
29
22
  end
30
23
 
@@ -0,0 +1,149 @@
1
+ require 'net/http'
2
+ require 'oauth'
3
+
4
+ module Hatenablog
5
+ module Requester
6
+ class RequestError < StandardError; end
7
+
8
+ def self.create(config)
9
+ if config.auth_type == 'basic'
10
+ Requester::Basic.new(config.user_id, config.api_key)
11
+ else
12
+ consumer = ::OAuth::Consumer.new(config.consumer_key, config.consumer_secret)
13
+ Requester::OAuth.new(::OAuth::AccessToken.new(consumer, config.access_token, config.access_token_secret))
14
+ end
15
+ end
16
+
17
+ class OAuth
18
+ # Create a new OAuth 1.0a access token.
19
+ # @param [OAuth::AccessToken] access_token access token object
20
+ def initialize(access_token)
21
+ @access_token = access_token
22
+ end
23
+
24
+ # HTTP GET method
25
+ # @param [string] uri target URI
26
+ # @return [Net::HTTPResponse] HTTP response
27
+ def get(uri)
28
+ begin
29
+ response = @access_token.get(uri)
30
+ rescue => problem
31
+ raise RequestError, 'Fail to GET: ' + problem.to_s
32
+ end
33
+ response
34
+ end
35
+
36
+ # HTTP POST method
37
+ # @param [string] uri target URI
38
+ # @param [string] body HTTP request body
39
+ # @param [string] headers HTTP request headers
40
+ # @return [Net::HTTPResponse] HTTP response
41
+ def post(uri,
42
+ body = '',
43
+ headers = { 'Content-Type' => 'application/atom+xml; type=entry' } )
44
+ begin
45
+ response = @access_token.post(uri, body, headers)
46
+ rescue => problem
47
+ raise RequestError, 'Fail to POST: ' + problem.to_s
48
+ end
49
+ response
50
+ end
51
+
52
+ # HTTP PUT method
53
+ # @param [string] uri target URI
54
+ # @param [string] body HTTP request body
55
+ # @param [string] headers HTTP request headers
56
+ # @return [Net::HTTPResponse] HTTP response
57
+ def put(uri,
58
+ body = '',
59
+ headers = { 'Content-Type' => 'application/atom+xml; type=entry' } )
60
+ begin
61
+ response = @access_token.put(uri, body, headers)
62
+ rescue => problem
63
+ raise RequestError, 'Fail to PUT: ' + problem.to_s
64
+ end
65
+ response
66
+ end
67
+
68
+ # HTTP DELETE method
69
+ # @param [string] uri target URI
70
+ # @param [string] headers HTTP request headers
71
+ # @return [Net::HTTPResponse] HTTP response
72
+ def delete(uri,
73
+ headers = { 'Content-Type' => 'application/atom+xml; type=entry' })
74
+ begin
75
+ response = @access_token.delete(uri, headers)
76
+ rescue => problem
77
+ raise RequestError, 'Fail to DELETE: ' + problem.to_s
78
+ end
79
+ response
80
+ end
81
+ end
82
+
83
+ class Basic
84
+ METHODS = {
85
+ get: Net::HTTP::Get,
86
+ post: Net::HTTP::Post,
87
+ put: Net::HTTP::Put,
88
+ delete: Net::HTTP::Delete
89
+ }
90
+
91
+ # Create a new Basic authentication requester.
92
+ # @params [string] user_id Hatena user ID
93
+ # @params [string] api_key Hatena API key
94
+ def initialize(user_id, api_key)
95
+ @user_id = user_id
96
+ @api_key = api_key
97
+ end
98
+
99
+ # HTTP GET method
100
+ # @param [string] uri target URI
101
+ # @return [Net::HTTPResponse] HTTP response
102
+ def get(uri)
103
+ request(uri, :get)
104
+ end
105
+
106
+ # HTTP POST method
107
+ # @param [string] uri target URI
108
+ # @param [string] body HTTP request body
109
+ # @param [string] headers HTTP request headers
110
+ # @return [Net::HTTPResponse] HTTP response
111
+ def post(uri, body, headers = nil)
112
+ request(uri, :post, body: body, headers: headers)
113
+ end
114
+
115
+ # HTTP PUT method
116
+ # @param [string] uri target URI
117
+ # @param [string] body HTTP request body
118
+ # @param [string] headers HTTP request headers
119
+ # @return [Net::HTTPResponse] HTTP response
120
+ def put(uri, body, headers = nil )
121
+ request(uri, :put, body: body, headers: headers)
122
+ end
123
+
124
+ # HTTP DELETE method
125
+ # @param [string] uri target URI
126
+ # @param [string] headers HTTP request headers
127
+ # @return [Net::HTTPResponse] HTTP response
128
+ def delete(uri, headers = nil)
129
+ request(uri, :delete, headers: headers)
130
+ end
131
+
132
+ private
133
+ def request(uri, method, body: nil, headers: nil)
134
+ uri = URI(uri)
135
+ req = METHODS[method].new(uri, headers)
136
+ req.basic_auth @user_id, @api_key
137
+ if body
138
+ req.body = body
139
+ req.content_type = 'application/atom+xml; type=entry'
140
+ end
141
+
142
+ http = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.port == 443)
143
+ http.request(req)
144
+ rescue => problem
145
+ raise RequestError, "Fail to #{method.upcase}: " + problem.to_s
146
+ end
147
+ end
148
+ end
149
+ end
@@ -1,3 +1,3 @@
1
1
  module Hatenablog
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hatenablog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kohei Yamamoto
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-08-16 00:00:00.000000000 Z
11
+ date: 2016-10-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -146,6 +146,7 @@ files:
146
146
  - lib/hatenablog/configuration.rb
147
147
  - lib/hatenablog/entry.rb
148
148
  - lib/hatenablog/feed.rb
149
+ - lib/hatenablog/requester.rb
149
150
  - lib/hatenablog/version.rb
150
151
  homepage: https://github.com/kymmt90/hatenablog
151
152
  licenses: