wordpress_client 0.0.1 → 1.0.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: db9e904a3d97870c4ca1077dd350b7466ed63716
4
- data.tar.gz: a40076833498ef6f90faa6a592da1cb4898d6972
3
+ metadata.gz: 07d49e4293481ae704072d12288a60a97d1182ec
4
+ data.tar.gz: be101dbc5a42658d3b9639bf0cc6d1753f246d00
5
5
  SHA512:
6
- metadata.gz: 539fb8ba5bceeb76a86b32336792a79ffd7df4c8a2a0abb1a2632fdf64aac1d0a4fe8720c3036697f0248746e00e9f30742b9efcc30c43e61ee8b8bed29341ff
7
- data.tar.gz: c456230269ebcac532ca2d4b7e141134822243240f620b4d3cb06f5067a29a3c05b16246ad5cd38cbe19ca1484863e57c4bd20e46b534da27adb49143a279ac6
6
+ metadata.gz: 8cec642f556f04ff4f5c418dda5c560956b7a1c1d3cd17184a2312a0a9d35daf5c9fb60834055375d3b27b0c1623d74b3b9bf860adb9334bc476d2c22b13f87a
7
+ data.tar.gz: d149bb98f48f1f164aef95cbad14d60669b553abd78f2968ccae16be2e0582d887d2af3b1e81f8dda8fa29e69958530a95dfe37168020ac04b40a3a8ba73f709
data/.codeclimate.yml ADDED
@@ -0,0 +1,14 @@
1
+ ---
2
+ engines:
3
+ rubocop:
4
+ enabled: true
5
+ bundler-audit:
6
+ enabled: true
7
+ fixme:
8
+ enabled: true
9
+ ratings:
10
+ paths:
11
+ - lib/**/*.rb
12
+ exclude_paths:
13
+ - spec/**/*
14
+ - ".*"
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --no-private --embed-mixins
data/Changelog.md ADDED
@@ -0,0 +1,3 @@
1
+ # 1.0.0
2
+
3
+ * Initial release
data/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # WordpressClient
2
2
 
3
- WordpressClient is a very simple client to the Wordpress API, version 2 beta 8.0.
3
+ WordpressClient is a very simple client for the Wordpress [WP REST API plugin][api] (version 2 beta 8.0).
4
4
 
5
- **NOTE:** The repository is still named `wpclient` as we're in the middle of a rename. Some references might persist until it's completed.
6
-
7
- [![Circle CI](https://circleci.com/gh/hemnet/wpclient.svg?style=svg)](https://circleci.com/gh/hemnet/wpclient) [![Code Climate](https://codeclimate.com/repos/5645938269568041da00cded/badges/5e870b57428f23c1f2ff/gpa.svg)](https://codeclimate.com/repos/5645938269568041da00cded/feed) [![Test Coverage](https://codeclimate.com/repos/5645938269568041da00cded/badges/5e870b57428f23c1f2ff/coverage.svg)](https://codeclimate.com/repos/5645938269568041da00cded/coverage)
5
+ [![Circle CI](https://circleci.com/gh/hemnet/wordpress_client.svg?style=svg)](https://circleci.com/gh/hemnet/wordpress_client) [![Code Climate](https://codeclimate.com/repos/5645938269568041da00cded/badges/5e870b57428f23c1f2ff/gpa.svg)](https://codeclimate.com/repos/5645938269568041da00cded/feed) [![Test Coverage](https://codeclimate.com/repos/5645938269568041da00cded/badges/5e870b57428f23c1f2ff/coverage.svg)](https://codeclimate.com/repos/5645938269568041da00cded/coverage) [![Gem Version](https://badge.fury.io/rb/wordpress_client.svg)](https://badge.fury.io/rb/wordpress_client)
8
6
 
9
7
  ## Usage
10
8
 
11
- Initialize a client with a username, password and API URL. You can then search for posts.
9
+ **[Read the full API documentation][docs]**
10
+
11
+ Initialize a client with a user name, password and API URL. You can then search for posts.
12
12
 
13
13
  ```ruby
14
14
  client = WordpressClient.new(url: "https://example.com/wp-json/", username: "example", password: "example")
@@ -36,7 +36,7 @@ updated_post.title_html # => "Updated"
36
36
 
37
37
  You need to install Docker and set it up for your machine. Note that you need `docker-machine` to run Docker on OS X.
38
38
 
39
- Run tests using the normal `rspec` command after installing all bundles. The first time the integration tests are run, a docker image will be built that hosts a Wordpress installation, but the image will be re-used on subsequent runs.
39
+ Run tests using the normal `rspec` command after installing all bundles.
40
40
 
41
41
  ```
42
42
  bundle exec rspec
@@ -52,6 +52,12 @@ end
52
52
 
53
53
  The normal `rspec` command will *not* use this filter in case it is ever committed accidentally, so CI can catch any problems.
54
54
 
55
+ ## Releasing a new version
56
+
57
+ The normal gem release cycle works using `rake release`.
58
+
59
+ If you make changes to the docker image, you can release it using `rake docker:release`.
60
+
55
61
  ## Copyright & License
56
62
 
57
63
  Copyright © 2015 Hemnet Service HNS AB
@@ -61,3 +67,6 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
61
67
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
62
68
 
63
69
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
70
+
71
+ [api]: http://v2.wp-api.org/
72
+ [docs]: http://www.rubydoc.info/gems/wordpress_client/
data/Rakefile CHANGED
@@ -1 +1,36 @@
1
1
  require "bundler/gem_tasks"
2
+ require "yard"
3
+ require "wordpress_client/version"
4
+
5
+ YARD::Rake::YardocTask.new
6
+
7
+ namespace :docker do
8
+ DOCKER_DIR = File.expand_path("../spec/docker", __FILE__).freeze
9
+ IMAGE_NAME = "hemnet/wordpress_client_test".freeze
10
+ DEV_IMAGE = [IMAGE_NAME, "dev"].join(":").freeze
11
+
12
+ desc "Build the docker image"
13
+ task :build do
14
+ sh "docker", "build", "-t", DEV_IMAGE, DOCKER_DIR
15
+ end
16
+
17
+ desc "Release current dev build"
18
+ task release: :build do
19
+ version = prompt "Which version do you want to release"
20
+ raise "Invalid version string" unless version =~ /\A[\d.]+\z/
21
+
22
+ latest = prompt "Do you want this to be the :latest release? [Y/n]"
23
+ latest = (latest.empty? || latest.downcase == "y")
24
+
25
+ sh "docker", "tag", DEV_IMAGE, "#{IMAGE_NAME}:#{version}"
26
+ sh "docker", "tag", "-f", DEV_IMAGE, "#{IMAGE_NAME}:latest" if latest
27
+
28
+ sh "docker", "push", "#{IMAGE_NAME}:#{version}"
29
+ sh "docker", "push", "#{IMAGE_NAME}:latest" if latest
30
+ end
31
+ end
32
+
33
+ def prompt(message)
34
+ print "#{message} > "
35
+ STDIN.gets.strip
36
+ end
@@ -19,7 +19,26 @@ require "wordpress_client/replace_terms"
19
19
  require "wordpress_client/replace_metadata"
20
20
 
21
21
  module WordpressClient
22
- def self.new(*args)
23
- Client.new(Connection.new(*args))
22
+ # Initialize a new client using the provided connection details.
23
+ # You need to provide authentication details, and the user must have +edit+
24
+ # permissions on the blog if you want to read Post Meta, or to modify
25
+ # anything.
26
+ #
27
+ # @example
28
+ # client = WordpressClient.new(
29
+ # url: "https://blog.example.com/wp-json",
30
+ # username: "bot",
31
+ # password: ENV.fetch("WORDPRESS_PASSWORD"),
32
+ # )
33
+ #
34
+ # @see Client Client, for the methods available after creating the connection.
35
+ #
36
+ # @param url [String] The base URL to the wordpress install, including
37
+ # +/wp-json+.
38
+ # @param username [String] A valid username on the wordpress installation.
39
+ # @param password [String] The password for the provided user.
40
+ # @return {Client}
41
+ def self.new(url:, username:, password:)
42
+ Client.new(Connection.new(url: url, username: username, password: password))
24
43
  end
25
44
  end
@@ -1,4 +1,6 @@
1
1
  module WordpressClient
2
+ # Represents a category from Wordpress.
3
+ # @see Term
2
4
  class Category < Term
3
5
  end
4
6
  end
@@ -4,6 +4,19 @@ module WordpressClient
4
4
  @connection = connection
5
5
  end
6
6
 
7
+ # @!group Posts
8
+
9
+ # Find {Post Posts} matching given parameters.
10
+ #
11
+ # @example Finding 5 posts in the Important category
12
+ # posts = client.posts(per_page: 5, category_slug: "important")
13
+ #
14
+ # @param page [Fixnum] Current page for pagination. Defaults to 1.
15
+ # @param per_page [Fixnum] Posts per page. Defaults to 10.
16
+ # @param category_slug [String, nil] Find posts belonging to a category with the given slug.
17
+ # @param tag_slug [String, nil] Find posts belonging to a tag with the given slug.
18
+ #
19
+ # @return {PaginatedCollection[Post]} Paginated collection of the found posts.
7
20
  def posts(per_page: 10, page: 1, category_slug: nil, tag_slug: nil)
8
21
  filter = {}
9
22
  filter[:category_name] = category_slug if category_slug
@@ -13,23 +26,21 @@ module WordpressClient
13
26
  )
14
27
  end
15
28
 
16
- def categories(per_page: 10, page: 1)
17
- connection.get_multiple(Category, "terms/category", page: page, per_page: per_page)
18
- end
19
-
20
- def tags(per_page: 10, page: 1)
21
- connection.get_multiple(Tag, "terms/tag", page: page, per_page: per_page)
22
- end
23
-
24
- def media(per_page: 10, page: 1)
25
- connection.get_multiple(Media, "media", page: page, per_page: per_page)
26
- end
27
-
29
+ # Find the {Post} with the given ID, or raises an error if not found.
30
+ #
31
+ # @return {Post}
32
+ # @raise {NotFoundError}
33
+ # @raise {subclasses of Error} on other unexpected errors
28
34
  def find_post(id)
29
35
  connection.get(Post, "posts/#{id.to_i}", _embed: nil, context: "edit")
30
36
  end
31
37
 
32
- def find_by_slug(slug)
38
+ # Find the first {Post} with the given slug, or raises an error if it cannot be found.
39
+ #
40
+ # @return {Post}
41
+ # @raise {NotFoundError}
42
+ # @raise {subclasses of Error} on other unexpected errors
43
+ def find_post_by_slug(slug)
33
44
  posts = connection.get_multiple(
34
45
  Post, "posts", per_page: 1, page: 1, filter: {name: slug}, _embed: nil
35
46
  )
@@ -40,18 +51,27 @@ module WordpressClient
40
51
  end
41
52
  end
42
53
 
43
- def find_category(id)
44
- connection.get(Category, "terms/category/#{id.to_i}")
45
- end
46
-
47
- def find_tag(id)
48
- connection.get(Tag, "terms/tag/#{id.to_i}")
49
- end
50
-
51
- def find_media(id)
52
- connection.get(Media, "media/#{id.to_i}")
53
- end
54
-
54
+ # Create a new {Post} with the given attributes in Wordpress and return it.
55
+ #
56
+ # In addition to {http://v2.wp-api.org/reference/posts/ the accepted
57
+ # parameters of the API}, this method also takes the following keys:
58
+ # * +:meta+
59
+ # * +:category_ids+
60
+ # * +:tag_ids+
61
+ #
62
+ # @see http://v2.wp-api.org/reference/posts/ List of accepted parameters
63
+ # @param attributes [Hash<Symbol,Object>] attribute list, containing
64
+ # accepted parameters or the custom parameters listed
65
+ # above.
66
+ # @option attributes [Hash<String,String>] meta Hash of meta values.
67
+ # @option attributes [Array<Fixnum>] category_ids List of category IDs the
68
+ # Post should belong to.
69
+ # @option attributes [Array<Fixnum>] tag_ids List of tag IDs the Post
70
+ # should have.
71
+ #
72
+ # @return {Post}
73
+ # @raise {ValidationError}
74
+ # @raise {subclasses of Error} on other unexpected errors
55
75
  def create_post(attributes)
56
76
  post = connection.create(Post, "posts", attributes, redirect_params: {_embed: nil})
57
77
 
@@ -67,14 +87,34 @@ module WordpressClient
67
87
  end
68
88
  end
69
89
 
70
- def create_category(attributes)
71
- connection.create(Category, "terms/category", attributes)
72
- end
73
-
74
- def create_tag(attributes)
75
- connection.create(Tag, "terms/tag", attributes)
76
- end
77
-
90
+ # Update the {Post} with the given id, setting the supplied attributes in
91
+ # Wordpress and returning an updated Post.
92
+ #
93
+ # In addition to {http://v2.wp-api.org/reference/posts/ the accepted
94
+ # parameters of the API}, this method also takes the following keys:
95
+ # * +:meta+
96
+ # * +:category_ids+
97
+ # * +:tag_ids+
98
+ #
99
+ # @example Changing the title of a Post
100
+ # new_post = client.update_post(post.id, title: "A better title")
101
+ # new_post.title_html #=> "A better title"
102
+ #
103
+ # @see http://v2.wp-api.org/reference/posts/ List of accepted parameters
104
+ # @param id [Fixnum] ID of the post to update.
105
+ # @param attributes [Hash<Symbol,Object>] attribute list, containing
106
+ # accepted parameters or the custom parameters listed
107
+ # above.
108
+ # @option attributes [Hash<String,String>] meta Hash of meta values.
109
+ # @option attributes [Array<Fixnum>] category_ids List of category IDs the
110
+ # Post should belong to.
111
+ # @option attributes [Array<Fixnum>] tag_ids List of tag IDs the Post
112
+ # should have.
113
+ #
114
+ # @return {Post}
115
+ # @raise {NotFoundError}
116
+ # @raise {ValidationError}
117
+ # @raise {subclasses of Error} on other unexpected errors
78
118
  def update_post(id, attributes)
79
119
  post = connection.patch(Post, "posts/#{id.to_i}?_embed", attributes)
80
120
 
@@ -90,22 +130,180 @@ module WordpressClient
90
130
  end
91
131
  end
92
132
 
133
+ # Deletes the {Post} with the given ID.
134
+ #
135
+ # @param id [Fixnum] The {Post} ID.
136
+ # @param force [Boolean] When +false+, the Post will be put in the "Trash"
137
+ # of Wordpress. +true+ causes the Post to be irrevocably deleted.
138
+ #
139
+ # @return true always
140
+ def delete_post(id, force: false)
141
+ connection.delete("posts/#{id.to_i}", {"force" => force})
142
+ end
143
+
144
+ # @!group Categories
145
+
146
+ # Find {Category Categories} in the Wordpress install.
147
+ #
148
+ # @return {PaginatedCollection[Category]}
149
+ def categories(per_page: 10, page: 1)
150
+ connection.get_multiple(Category, "terms/category", page: page, per_page: per_page)
151
+ end
152
+
153
+ # Find {Category} with the given ID.
154
+ #
155
+ # @return {Category}
156
+ # @raise {NotFoundError}
157
+ # @raise {subclasses of Error} on other unexpected errors
158
+ def find_category(id)
159
+ connection.get(Category, "terms/category/#{id.to_i}")
160
+ end
161
+
162
+ # Create a new {Category} with the given attributes.
163
+ #
164
+ # @see http://v2.wp-api.org/reference/taxonomies/ List of accepted parameters
165
+ # @param attributes [Hash<Symbol,Object>] attribute list, containing
166
+ # parameters accepted by the API.
167
+ # @option attributes [String] name Name of the category (required).
168
+ # @option attributes [String] slug Slug of the category (optional).
169
+ # @option attributes [String] description Description of the category (optional).
170
+ #
171
+ # @return {Category} the new Category
172
+ # @raise {ValidationError}
173
+ # @raise {subclasses of Error} on other unexpected errors
174
+ def create_category(attributes)
175
+ connection.create(Category, "terms/category", attributes)
176
+ end
177
+
178
+ # Update the {Category} with the given id, setting the supplied attributes.
179
+ #
180
+ # @see http://v2.wp-api.org/reference/taxonomies/ List of accepted parameters
181
+ # @param attributes [Hash<Symbol,Object>] attribute list, containing
182
+ # parameters accepted by the API.
183
+ # @option attributes [String] name Name of the category.
184
+ # @option attributes [String] slug Slug of the category.
185
+ # @option attributes [String] description Description of the category.
186
+ #
187
+ # @return {Category} the updated Category
188
+ # @raise {NotFoundError}
189
+ # @raise {ValidationError}
190
+ # @raise {subclasses of Error} on other unexpected errors
93
191
  def update_category(id, attributes)
94
192
  connection.patch(Category, "terms/category/#{id.to_i}", attributes)
95
193
  end
96
194
 
195
+ # @!group Tags
196
+
197
+ # Find {Tag Tags} in the Wordpress install.
198
+ #
199
+ # @return {PaginatedCollection[Tag]}
200
+ def tags(per_page: 10, page: 1)
201
+ connection.get_multiple(Tag, "terms/tag", page: page, per_page: per_page)
202
+ end
203
+
204
+ # Find {Tag} with the given ID.
205
+ #
206
+ # @return {Tag}
207
+ # @raise {NotFoundError}
208
+ # @raise {subclasses of Error} on other unexpected errors
209
+ def find_tag(id)
210
+ connection.get(Tag, "terms/tag/#{id.to_i}")
211
+ end
212
+
213
+ # Create a new {Tag} with the given attributes.
214
+ #
215
+ # @see http://v2.wp-api.org/reference/taxonomies/ List of accepted parameters
216
+ # @param attributes [Hash<Symbol,Object>] attribute list, containing
217
+ # parameters accepted by the API.
218
+ # @option attributes [String] name Name of the tag (required).
219
+ # @option attributes [String] slug Slug of the tag (optional).
220
+ # @option attributes [String] description Description of the tag (optional).
221
+ #
222
+ # @return {Tag} the new Tag
223
+ # @raise {ValidationError}
224
+ # @raise {subclasses of Error} on other unexpected errors
225
+ def create_tag(attributes)
226
+ connection.create(Tag, "terms/tag", attributes)
227
+ end
228
+
229
+ # Update the {Tag} with the given id, setting the supplied attributes.
230
+ #
231
+ # @see http://v2.wp-api.org/reference/taxonomies/ List of accepted parameters
232
+ # @param attributes [Hash<Symbol,Object>] attribute list, containing
233
+ # parameters accepted by the API.
234
+ # @option attributes [String] name Name of the tag.
235
+ # @option attributes [String] slug Slug of the tag.
236
+ # @option attributes [String] description Description of the tag.
237
+ #
238
+ # @return {Tag} the updated Tag
239
+ # @raise {NotFoundError}
240
+ # @raise {ValidationError}
241
+ # @raise {subclasses of Error} on other unexpected errors
97
242
  def update_tag(id, attributes)
98
243
  connection.patch(Tag, "terms/tag/#{id.to_i}", attributes)
99
244
  end
100
245
 
101
- def update_media(id, attributes)
102
- connection.patch(Media, "media/#{id.to_i}", attributes)
246
+ # @!group Media
247
+
248
+ # Find {Media} in the Wordpress install.
249
+ #
250
+ # @return {PaginatedCollection[Media]}
251
+ def media(per_page: 10, page: 1)
252
+ connection.get_multiple(Media, "media", page: page, per_page: per_page)
103
253
  end
104
254
 
255
+ # Find {Media} with the given ID.
256
+ #
257
+ # @return {Media}
258
+ # @raise {NotFoundError}
259
+ # @raise {subclasses of Error} on other unexpected errors
260
+ def find_media(id)
261
+ connection.get(Media, "media/#{id.to_i}")
262
+ end
263
+
264
+ # Create a new {Media} by uploading a IO stream.
265
+ #
266
+ # You need to provide both MIME type and filename for Wordpress to accept
267
+ # the file.
268
+ #
269
+ # @example Uploading a JPEG from a request
270
+ # media = client.upload(
271
+ # request.body_stream, filename: "foo.jpg", mime_type: "image/jpeg"
272
+ # )
273
+ #
274
+ # @param io [IO-like object] IO stream (for example an open file) that will
275
+ # be the body of the media.
276
+ # @param mime_type [String] the MIME type of the IO stream
277
+ # @param filename [String] the filename that Wordpress should see. Requires
278
+ # a file extension to make Wordpress happy.
279
+ #
280
+ # @return {Media} the new Media
281
+ # @raise {ValidationError}
282
+ # @raise {subclasses of Error} on other unexpected errors
283
+ # @see #upload_file #upload_file - a shortcut for uploading files on disk
105
284
  def upload(io, mime_type:, filename:)
106
285
  connection.upload(Media, "media", io, mime_type: mime_type, filename: filename)
107
286
  end
108
287
 
288
+ # Create a new {Media} by uploading a file from disk.
289
+ #
290
+ # You need to provide MIME type for Wordpress to accept the file. The
291
+ # filename that Wordpress sees will automatically be derived from the
292
+ # passed path.
293
+ #
294
+ # @example Uploading a JPEG from disk
295
+ # media = client.upload_file(
296
+ # "assets/ocean.jpg", mime_type: "image/jpeg"
297
+ # )
298
+ #
299
+ # @param filename [String] a path to a readable file.
300
+ # @param mime_type [String] the MIME type of the file.
301
+ #
302
+ # @return {Media} the new Media
303
+ # @raise {ValidationError}
304
+ # @raise {subclasses of Error} on other unexpected errors
305
+ # @see #upload #upload - for when you want to upload something that isn't a
306
+ # file on disk, or need extra flexibility
109
307
  def upload_file(filename, mime_type:)
110
308
  path = filename.to_s
111
309
  File.open(path, 'r') do |file|
@@ -113,10 +311,22 @@ module WordpressClient
113
311
  end
114
312
  end
115
313
 
116
- def delete_post(id, force: false)
117
- connection.delete("posts/#{id.to_i}", {"force" => force})
314
+ # Update the {Media} with the given id, setting the supplied attributes.
315
+ #
316
+ # @see http://v2.wp-api.org/reference/media/ List of accepted parameters
317
+ # @param attributes [Hash<Symbol,Object>] attribute list, containing
318
+ # parameters accepted by the API.
319
+ #
320
+ # @return {Media} The updated Media
321
+ # @raise {NotFoundError}
322
+ # @raise {ValidationError}
323
+ # @raise {subclasses of Error} on other unexpected errors
324
+ def update_media(id, attributes)
325
+ connection.patch(Media, "media/#{id.to_i}", attributes)
118
326
  end
119
327
 
328
+ # @!endgroup
329
+
120
330
  def inspect
121
331
  "#<WordpressClient::Client #{connection.inspect}>"
122
332
  end
@@ -2,6 +2,7 @@ require "faraday"
2
2
  require "json"
3
3
 
4
4
  module WordpressClient
5
+ # @private
5
6
  class Connection
6
7
  attr_reader :url, :username
7
8
 
@@ -1,10 +1,45 @@
1
1
  module WordpressClient
2
- Error = Class.new(::StandardError)
2
+ # Base class for all errors emitted from this gem. Rescue this in order to
3
+ # catch everything.
4
+ #
5
+ # See the list of subclasses for more specific error types.
6
+ class Error < ::StandardError; end
3
7
 
4
- UnauthorizedError = Class.new(Error)
8
+ # Raised when the clients attempt to do something that the user isn't
9
+ # authorized to do.
10
+ #
11
+ # This could happen if you try to delete a post and the user only has
12
+ # read-only access, for example.
13
+ # It would also happen if you provide bad authentication details.
14
+ #
15
+ # @see Error
16
+ class UnauthorizedError < Error; end
5
17
 
6
- TimeoutError = Class.new(Error)
7
- ServerError = Class.new(Error)
8
- NotFoundError = Class.new(Error)
9
- ValidationError = Class.new(Error)
18
+ # Raised when a request times out.
19
+ #
20
+ # @see Error
21
+ class TimeoutError < Error; end
22
+
23
+ # Raised when the server had an error, or when the server returned something
24
+ # unexpected, despite saying everything went okay. It's the most generic
25
+ # "Something went wrong with the request" error.
26
+ #
27
+ # @see Error
28
+ class ServerError < Error; end
29
+
30
+ # Raised when trying to find a resource that doesn't exist. It will also
31
+ # happen when you try to update a resource that doesn't exist.
32
+ #
33
+ # Lack of authorization can also mask actual resources so it appears that
34
+ # they don't exist.
35
+ #
36
+ # @see Error
37
+ class NotFoundError < Error; end
38
+
39
+ # Raised when the server rejects the body of a request. The error message
40
+ # will often include information about why the body was rejected, but it is
41
+ # not guaranteed.
42
+ #
43
+ # @see Error
44
+ class ValidationError < Error; end
10
45
  end
@@ -1,4 +1,5 @@
1
1
  module WordpressClient
2
+ # Represents a media record in Wordpress.
2
3
  class Media
3
4
  attr_accessor(
4
5
  :id, :slug, :title_html, :description,
@@ -6,10 +7,41 @@ module WordpressClient
6
7
  :guid, :link, :media_details
7
8
  )
8
9
 
10
+ # @!attribute [rw] title_html
11
+ # @return [String] the title of the media, HTML escaped
12
+ # @example
13
+ # media.title_html #=> "Sunset &mdash; Painting by some person"
14
+
15
+ # @!attribute [rw] date
16
+ # @return [Time, nil] the date of the media, in UTC if available
17
+
18
+ # @!attribute [rw] updated_at
19
+ # @return [Time, nil] the modification date of the media, in UTC if available
20
+
21
+ # @!attribute [rw] guid
22
+ # Returns the permalink/GUID – or +source_url+ – of the media.
23
+ #
24
+ # Media that are embedded in posts have a +source_url+ attribute and no
25
+ # +guid+, and stand-alone media has a +guid+ but no +source_url+. They
26
+ # are both backed by the same data, so this method handles both cases,
27
+ # and is aliased to both names.
28
+ #
29
+ # @return [String] the permalink/GUID – or +source_url+ – of the media
30
+
31
+ # @!attribute [rw] media_details
32
+ # Returns the media details if available.
33
+ #
34
+ # Media details cannot be documented here. It's up to you to handle this
35
+ # generic "payload" attribute the best way you can.
36
+ #
37
+ # @return [Hash<String,Object>] the media details returned from the server
38
+
39
+ # @api private
9
40
  def self.parse(data)
10
41
  MediaParser.parse(data)
11
42
  end
12
43
 
44
+ # Creates a new instance, populating the fields with the passed values.
13
45
  def initialize(
14
46
  id: nil,
15
47
  slug: nil,
@@ -1,4 +1,5 @@
1
1
  module WordpressClient
2
+ # @private
2
3
  class MediaParser
3
4
  include RestParser
4
5
 
@@ -1,9 +1,31 @@
1
1
  require "delegate"
2
2
 
3
3
  module WordpressClient
4
+ # Represents a paginated list of resources.
5
+ #
6
+ # @note This class has the full +Array+ interface by using
7
+ # +DelegateClass(Array)+. Methods do not show up in the documentation
8
+ # unless when manually documented.
4
9
  class PaginatedCollection < DelegateClass(Array)
10
+ # @!method size
11
+ # @return [Fixnum] the number of records actually in this "page".
12
+ # @see Array#size
13
+
5
14
  attr_reader :total, :current_page, :per_page
6
15
 
16
+ # @!attribute [r] total
17
+ # @return [Fixnum] the total hits in the full collection.
18
+ # @see #size #size is the size of the current "page".
19
+
20
+ # @!attribute [r] current_page
21
+ # @return [Fixnum] the current page number, where +1+ is the first page.
22
+
23
+ # @!attribute [r] per_page
24
+ # @return [Fixnum] the current page size setting, for example +30+.
25
+
26
+ # Create a new collection using the passed array +entries+.
27
+ #
28
+ # @param entries [Array] the original "page" array
7
29
  def initialize(entries, total:, current_page:, per_page:)
8
30
  super(entries)
9
31
  @total = total
@@ -11,12 +33,15 @@ module WordpressClient
11
33
  @per_page = per_page
12
34
  end
13
35
 
14
- #
15
- # Pagination methods. Fulfilling will_paginate protocol
16
- #
36
+ # @!group will_paginate protocol
17
37
 
18
38
  alias total_entries total
19
39
 
40
+ # @note This method is used by +will_paginate+. By implementing this
41
+ # interface, you can use a {PaginatedCollection} in place of a
42
+ # +WillPaginate::Collection+ to render pagination details.
43
+ # @return [Fixnum] the total number of pages that can show the {#total}
44
+ # entries with {#per_page} records per page. +0+ if no entries.
20
45
  def total_pages
21
46
  if total.zero? || per_page.zero?
22
47
  0
@@ -25,23 +50,53 @@ module WordpressClient
25
50
  end
26
51
  end
27
52
 
53
+ # @note This method is used by +will_paginate+. By implementing this
54
+ # interface, you can use a {PaginatedCollection} in place of a
55
+ # +WillPaginate::Collection+ to render pagination details.
56
+ # @return [Fixnum, nil] the next page number or +nil+ if on last page.
28
57
  def next_page
29
58
  if current_page < total_pages
30
59
  current_page + 1
31
60
  end
32
61
  end
33
62
 
63
+ # @note This method is used by +will_paginate+. By implementing this
64
+ # interface, you can use a {PaginatedCollection} in place of a
65
+ # +WillPaginate::Collection+ to render pagination details.
66
+ # @return [Fixnum, nil] the previous page number or +nil+ if on first page.
34
67
  def previous_page
35
68
  if current_page > 1
36
69
  current_page - 1
37
70
  end
38
71
  end
39
72
 
73
+ # @note This method is used by +will_paginate+. By implementing this
74
+ # interface, you can use a {PaginatedCollection} in place of a
75
+ # +WillPaginate::Collection+ to render pagination details.
76
+ # @return [Boolean] if the current page is out of bounds, e.g. less than 1
77
+ # or higher than {#total_pages}.
40
78
  def out_of_bounds?
41
79
  current_page < 1 || current_page > total_pages
42
80
  end
43
81
 
44
- # will_paginate < 3.0 has this method
82
+ # @note This method is used by +will_paginate+. By implementing this
83
+ # interface, you can use a {PaginatedCollection} in place of a
84
+ # +WillPaginate::Collection+ to render pagination details.
85
+ #
86
+ # @note will_paginate < 3.0 has this method, but it's no longer present in
87
+ # newer will_paginate.
88
+ #
89
+ # Returns the offset of the current page.
90
+ #
91
+ # @example First page offset
92
+ # collection.per_page # => 20
93
+ # collection.current_page # => 1
94
+ # collection.offset #=> 0
95
+ # @example Later offset
96
+ # collection.per_page # => 20
97
+ # collection.current_page # => 3
98
+ # collection.offset #=> 40
99
+ #
45
100
  def offset
46
101
  if current_page > 0
47
102
  (current_page - 1) * per_page
@@ -49,5 +104,7 @@ module WordpressClient
49
104
  0
50
105
  end
51
106
  end
107
+
108
+ # @!endgroup
52
109
  end
53
110
  end
@@ -1,6 +1,9 @@
1
1
  require "time"
2
2
 
3
3
  module WordpressClient
4
+ # Represents a post in Wordpress.
5
+ #
6
+ # @see http://v2.wp-api.org/reference/posts/ API documentation for Post
4
7
  class Post
5
8
  attr_accessor(
6
9
  :id, :slug, :url, :guid, :status,
@@ -9,10 +12,60 @@ module WordpressClient
9
12
  :categories, :tags, :meta, :featured_image
10
13
  )
11
14
 
15
+ # @!attribute [rw] title_html
16
+ # @return [String] the title of the media, HTML escaped
17
+ # @example
18
+ # post.title_html #=> "Fire &amp; diamonds!"
19
+
20
+ # @!attribute [rw] date
21
+ # @return [Time, nil] the date of the post, in UTC if available
22
+
23
+ # @!attribute [rw] updated_at
24
+ # @return [Time, nil] the modification date of the post, in UTC if available
25
+
26
+ # @!attribute [rw] guid
27
+ # @return [String] the permalink/GUID of the post for internal addressing
28
+ # @see #url
29
+
30
+ # @!attribute [rw] url
31
+ # @return [String] the URL (link) to the post
32
+
33
+ # @!attribute [rw] status
34
+ # @return ["publish", "future", "draft", "pending", "private", nil] the
35
+ # current status of the post, or +nil+ if undetermined
36
+
37
+ # @!attribute [rw] categories
38
+ # @return [Array[Category]] the {Category Categories} the post belongs to.
39
+ # @see Category
40
+
41
+ # @!attribute [rw] tags
42
+ # @return [Array[Tag]] the {Tag Tags} the post belongs to.
43
+ # @see Tag
44
+
45
+ # @!attribute [rw] featured_image
46
+ # @return [Media, nil] the featured image, as an instance of {Media}
47
+ # @see Media
48
+
49
+ # @!attribute [rw] meta
50
+ # Returns the Post meta, as a +Hash+ of +String => String+.
51
+ #
52
+ # @example
53
+ # post.meta # => {"Mood" => "Happy", "reviewed_by" => "user:45"}
54
+ #
55
+ # @return [Hash<String,String>] the post meta, as a Hash.
56
+ # @see Category
57
+ # @see Client#update_post
58
+
59
+ # @!attribute [rw] meta_ids
60
+ # @api private
61
+ # Backs the {#meta_id_for} method. Used when constructing requests.
62
+
63
+ # @api private
12
64
  def self.parse(data)
13
65
  PostParser.parse(data)
14
66
  end
15
67
 
68
+ # Construct a new instance with the given attributes.
16
69
  def initialize(
17
70
  id: nil,
18
71
  slug: nil,
@@ -47,14 +100,32 @@ module WordpressClient
47
100
  @meta_ids = meta_ids
48
101
  end
49
102
 
103
+ # A list of all category ids for the post.
104
+ #
105
+ # You can pass this list, with IDs added or removed, to
106
+ # {Client#update_post} to change the category list.
107
+ #
108
+ # @return [Array[Fixnum]] the id of every category associated with this post
109
+ # @see Client#update_post
50
110
  def category_ids() categories.map(&:id) end
51
111
 
112
+ # A list of all tag ids for the post.
113
+ #
114
+ # You can pass this list, with IDs added or removed, to
115
+ # {Client#update_post} to change the tag list.
116
+ #
117
+ # @return [Array[Fixnum]] the id of every tag associated with this post
118
+ # @see Client#update_post
52
119
  def tag_ids() tags.map(&:id) end
53
120
 
121
+ # @return [Fixnum, nil] ID of the featured image associated with the post.
54
122
  def featured_image_id
55
123
  featured_image && featured_image.id
56
124
  end
57
125
 
126
+ # @api private
127
+ # Used to determine the underlying ID of the different meta keys so they
128
+ # can be modified by {Client}. You should not use this for anything.
58
129
  def meta_id_for(key)
59
130
  @meta_ids[key] || raise(ArgumentError, "Post does not have meta #{key.inspect}")
60
131
  end
@@ -1,4 +1,5 @@
1
1
  module WordpressClient
2
+ # @private
2
3
  class PostParser
3
4
  include RestParser
4
5
 
@@ -1,6 +1,7 @@
1
1
  require "set"
2
2
 
3
3
  module WordpressClient
4
+ # @private
4
5
  class ReplaceMetadata
5
6
  def self.apply(connection, post, meta)
6
7
  instance = new(connection, post, meta)
@@ -1,6 +1,7 @@
1
1
  require "set"
2
2
 
3
3
  module WordpressClient
4
+ # @private
4
5
  class ReplaceTerms
5
6
  def self.apply_categories(connection, post, category_ids)
6
7
  instance = new(
@@ -1,4 +1,8 @@
1
1
  module WordpressClient
2
+ # @private
3
+ #
4
+ # Module included in other classes that need to parse result bodies from the
5
+ # WP API.
2
6
  module RestParser
3
7
  private
4
8
  def rendered(name)
@@ -1,4 +1,6 @@
1
1
  module WordpressClient
2
+ # Represents a tag from Wordpress.
3
+ # @see Term
2
4
  class Tag < Term
3
5
  end
4
6
  end
@@ -1,7 +1,27 @@
1
1
  module WordpressClient
2
+ # @abstract Implement a subclass for the resource type.
3
+ #
4
+ # Implementation for the abstract "term" in Wordpress.
5
+ #
6
+ # @see Category
7
+ # @see Tag
2
8
  class Term
3
9
  attr_reader :id, :name_html, :slug
4
10
 
11
+ # @!attribute [r] id
12
+ # @return [Fixnum] The ID of the resource in Wordpress.
13
+
14
+ # @!attribute [r] name_html
15
+ # @return [String] The name of the resource, HTML encoded.
16
+ # @example
17
+ # term.name_html #=> "Father &amp; Daughter stuff"
18
+
19
+ # @!attribute [r] slug
20
+ # @return [String] The slug of the resource in Wordpress.
21
+
22
+ # @api private
23
+ #
24
+ # Parses a data structure from a WP API response body into this term type.
5
25
  def self.parse(data)
6
26
  new(
7
27
  id: data.fetch("id"),
@@ -16,6 +36,15 @@ module WordpressClient
16
36
  @slug = slug
17
37
  end
18
38
 
39
+ # @api private
40
+ # Compares another instance. All attributes in this list must be equal for
41
+ # the instances to be equal:
42
+ #
43
+ # * +id+
44
+ # * +name_html+
45
+ # * +slug+
46
+ #
47
+ # One must also not be a subclass of the other; they must be the exact same class.
19
48
  def ==(other)
20
49
  if other.is_a? Term
21
50
  other.class == self.class &&
@@ -27,6 +56,7 @@ module WordpressClient
27
56
  end
28
57
  end
29
58
 
59
+ # Shows a nice representation of the term type.
30
60
  def inspect
31
61
  "#<#{self.class} ##{id} #{name_html.inspect} (#{slug})>"
32
62
  end
@@ -1,3 +1,7 @@
1
1
  module WordpressClient
2
- VERSION = "0.0.1"
2
+ # Current version of the gem.
3
+ #
4
+ # @note This only applies if using a released version. A development build
5
+ # would not correspond to this constant.
6
+ VERSION = "1.0.0"
3
7
  end
data/spec/client_spec.rb CHANGED
@@ -66,7 +66,7 @@ module WordpressClient
66
66
  Post, "posts", hash_including(filter: {name: "my-slug"})
67
67
  ).and_return [post]
68
68
 
69
- expect(client.find_by_slug("my-slug")).to eq post
69
+ expect(client.find_post_by_slug("my-slug")).to eq post
70
70
  end
71
71
 
72
72
  it "raises NotFoundError when trying to find by slug yields no posts" do
@@ -75,7 +75,7 @@ module WordpressClient
75
75
  ).and_return []
76
76
 
77
77
  expect {
78
- client.find_by_slug("my-slug")
78
+ client.find_post_by_slug("my-slug")
79
79
  }.to raise_error(NotFoundError, /my-slug/)
80
80
  end
81
81
  end
@@ -13,11 +13,14 @@ ENV APP_USER admin
13
13
  ENV APP_PASS P@ssw0rd
14
14
  ENV WP_KEY ILoveFlappyjacks
15
15
 
16
+ # Make pretty permalinks work so API is accessible
17
+ COPY htaccess /var/www/html/wordpress/.htaccess
18
+
16
19
  # Restore a copy of a set up database on first boot
17
20
  COPY dbdump.sql.gz /tmp/dbdump.sql.gz
18
21
  COPY restore-dbdump.sh /tmp/.restore-dbdump.sh
19
22
  RUN chmod +x /tmp/.restore-dbdump.sh && \
20
- echo "if [ -f /tmp/.restore-dbdump.sh ]; then /tmp/.restore-dbdump.sh; rm -fr /tmp/.restore-dbdump.sh; fi" >> /root/.bashrc
23
+ echo "if [ -f /tmp/.restore-dbdump.sh ]; then /tmp/.restore-dbdump.sh; rm /tmp/.restore-dbdump.sh; fi" >> /root/.bashrc
21
24
 
22
25
  ### Install API and API Basic Auth plugins
23
26
 
@@ -35,6 +38,3 @@ RUN curl -SL -o /tmp/rest-api.zip https://downloads.wordpress.org/plugin/rest-ap
35
38
  RUN curl -SL https://github.com/WP-API/Basic-Auth/archive/master.tar.gz \
36
39
  | tar -xzC /var/www/html/wordpress/wp-content/plugins/ \
37
40
  && mv /var/www/html/wordpress/wp-content/plugins/Basic-Auth* /var/www/html/wordpress/wp-content/plugins/basic-auth
38
-
39
- # Make pretty permalinks work so API is accessible
40
- COPY htaccess /var/www/html/wordpress/.htaccess
@@ -1,15 +1,47 @@
1
- # How this was built
1
+ # Docker image for WordpressClient
2
2
 
3
- ## dbdump
3
+ Use this docker image to run integration tests, either in this repo or in some client repo where you use the gem.
4
4
 
5
- If you need to regenerate the dbdump, remove the part where the file is copied and restored from the `Dockerfile`, then build and start the image.
5
+ **Note:** This image is not meant for *any* production use. It's meant for integration tests, and nothing else.
6
+
7
+ ## Usage
8
+
9
+ You need to publish the container's port 80 to whichever port you want your instance on, then set an environment variable for where the server should be accessible from as Wordpress needs to have this stored in the database.
10
+
11
+ You also need to run it with an interactive terminal in order for it to work.
12
+
13
+ ```bash
14
+ docker run -dit -p 8080:80 -e WORDPRESS_HOST=localhost:8080 hemnet/wordpress_client_test:latest
15
+ ```
16
+
17
+ I you want to see the ouput or access the environment in order to debug an issue, omit the `-d` option. It will boot into a `bash` shell with Apache running in the background. You can also use `docker attach` to attach to a running instance.
18
+
19
+ **Note:** When you exit a running container, everything stored in it will be kept on disk. It is recommended that you `docker rm` the image when you are done to clean up.
20
+
21
+ When the instance is up and running, you can log in as an administrator using `test`/`test` as username and password.
22
+
23
+ ## Contents
24
+
25
+ This image is based on Appcontainer's Wordpress image, which runs Apache, MySQL and PHP5 on CentOS using bash. In addition, a DB dump is restored containing a set up blog so you don't need to do the first installation steps.
26
+
27
+ * Username `test`
28
+ * Password `test`
29
+ * Plugin `WP-API` is installed
30
+ * Plugin `Basic-Auth` for `WP-API` installed
31
+ * `.htaccess` for Pretty Permalinks is set up so the API works
32
+
33
+ ## Developing the image
34
+
35
+ ### Re-creating DB dump from scratch
36
+
37
+ If you need to regenerate the DB dump, remove the part where the file is copied and restored from the `Dockerfile`, then build and start the image.
6
38
 
7
39
  ```bash
8
- docker build -t wpclient-test .
9
- docker run -it -p 8181:80 wpclient-test
40
+ docker build -t wordpress_client_test:dev .
41
+ docker run -it -p 8181:80 wordpress_client_test:dev
10
42
  ```
11
43
 
12
- You'll get a prompt inside the container. Open your browser and go to the newly booted application (`localhost:8181` if you have native Docker; otherwise go to your `$DOCKER_HOST_IP:8181` URL – see `echo $DOCKER_HOST` in your local shell).
44
+ You'll get a `bash` shell inside the container. Open your browser and go to the newly booted application (`localhost:8181` if you have native Docker; otherwise go to your `DOCKER_HOST_IP:8181` URL – see `echo $DOCKER_HOST` in your local shell).
13
45
 
14
46
  You'll be greeted by the Wordpress installer. Fill in everything and complete the installation.
15
47
 
@@ -22,16 +54,11 @@ mysqldump -u "$MYSQL_USER" --password="$MYSQL_PASS" --host="$MYSQL_HOST" "$MYSQL
22
54
  You can then copy the file to your host using the `docker cp` command:
23
55
 
24
56
  ```bash
25
- docker ps | grep wpclient-test
57
+ docker ps | grep wordpress_client_test:dev
26
58
  # See the container ID or name of your running container
27
59
  docker cp THE-CONTAINER-ID:/tmp/dbdump.sql.gz .
28
60
  ```
29
61
 
30
- You can then shut down your container by logging out of the container terminal.
31
-
32
- Restore the DB loading code from the `Dockerfile`, commit this file to the repo and rebuild everything and verify that Wordpress is still set up correctly when the dump is restored.
62
+ Last step is to update `restore-dbdump.sh` to replace the hard-coded `WORDPRESS_HOST` placeholder with the one you used to generate the DB dump with. This corresponds with `localhost:8181` with native Docker if you followed these commands exactly. If you use `docker-machine`, you need to use your machine IP instead. (See *"Usage"* above)
33
63
 
34
- `spec/docker/restore-dbdump.sh` hard codes an expectation that the IP in your
35
- datadump is a specfic IP. So you will need to change that hard coded
36
- expectation to match the new IP used in your data dump. You can find out what
37
- that IP is by examining the dumo but it is probably the value set in `$DOCKER_HOST`.
64
+ You can then shut down your container by logging out of the container terminal. Restore the DB loading code from the `Dockerfile`, commit this file to the repo and rebuild everything and verify that Wordpress is still set up correctly when the dump is restored.
@@ -64,13 +64,13 @@ describe "Posts (finding)" do
64
64
  describe "finding by slug" do
65
65
  it "finds the matching post" do
66
66
  post = client.create_post(title: "Oh hai", slug: "oh-hai")
67
- found = client.find_by_slug("oh-hai")
67
+ found = client.find_post_by_slug("oh-hai")
68
68
  expect(found.id).to eq post.id
69
69
  end
70
70
 
71
71
  it "raises NotFoundError when no post can be found" do
72
72
  expect {
73
- client.find_by_slug("clearly-does-not-exist-anywhere")
73
+ client.find_post_by_slug("clearly-does-not-exist-anywhere")
74
74
  }.to raise_error(WordpressClient::NotFoundError, /clearly/)
75
75
  end
76
76
 
@@ -79,7 +79,7 @@ describe "Posts (finding)" do
79
79
  title: "Updated title that doesn't match slug",
80
80
  slug: "original-concise-title",
81
81
  )
82
- found = client.find_by_slug("original-concise-title")
82
+ found = client.find_post_by_slug("original-concise-title")
83
83
  expect(found.id).to eq post.id
84
84
  end
85
85
  end
@@ -9,11 +9,15 @@ module DockerRunner
9
9
  end
10
10
 
11
11
  def image_exists?(name)
12
- system("docker images | grep -q '^#{name.shellescape} '")
12
+ name, tag = name.split(":", 2)
13
+ matcher = "^#{name} "
14
+ matcher << "[[:space:]]*#{tag}" if tag
15
+
16
+ system("docker images | grep -q #{matcher.shellescape}")
13
17
  end
14
18
 
15
19
  def build_image(name, path: Dir.pwd)
16
- system("cd #{path.shellescape} && docker build -t #{name.shellescape} .")
20
+ system("docker build -t #{name.shellescape} #{path.shellescape}")
17
21
  end
18
22
 
19
23
  def run_container(name, port:, environment: {})
@@ -24,6 +24,8 @@ class WordpressServer
24
24
  def password() "test" end
25
25
 
26
26
  private
27
+ DOCKER_IMAGE_NAME = "hemnet/wordpress_client_test:dev".freeze
28
+
27
29
  def host_with_port
28
30
  "#{host}:#{port}"
29
31
  end
@@ -62,14 +64,14 @@ class WordpressServer
62
64
  end
63
65
 
64
66
  def build_container_if_missing
65
- unless DockerRunner.image_exists?("wpclient-test")
66
- DockerRunner.build_image("wpclient-test", path: "spec/docker")
67
+ unless DockerRunner.image_exists?(DOCKER_IMAGE_NAME)
68
+ DockerRunner.build_image(DOCKER_IMAGE_NAME, path: "spec/docker")
67
69
  end
68
70
  end
69
71
 
70
72
  def start_container
71
73
  DockerRunner.run_container(
72
- "wpclient-test",
74
+ DOCKER_IMAGE_NAME,
73
75
  port: port,
74
76
  environment: {wordpress_host: host_with_port}
75
77
  )
@@ -24,4 +24,5 @@ Gem::Specification.new do |spec|
24
24
  spec.add_development_dependency "rake", "~> 10.0"
25
25
  spec.add_development_dependency "rspec", "~> 3.3"
26
26
  spec.add_development_dependency "webmock", "~> 1.22"
27
+ spec.add_development_dependency "yard", "~> 0.8.7"
27
28
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wordpress_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Magnus Bergmark
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-12-07 00:00:00.000000000 Z
12
+ date: 2015-12-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -81,6 +81,20 @@ dependencies:
81
81
  - - "~>"
82
82
  - !ruby/object:Gem::Version
83
83
  version: '1.22'
84
+ - !ruby/object:Gem::Dependency
85
+ name: yard
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: 0.8.7
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: 0.8.7
84
98
  description: A simple client to the Wordpress API.
85
99
  email:
86
100
  - magnus.bergmark@gmail.com
@@ -89,10 +103,13 @@ executables: []
89
103
  extensions: []
90
104
  extra_rdoc_files: []
91
105
  files:
106
+ - ".codeclimate.yml"
92
107
  - ".gitignore"
93
108
  - ".hound.yml"
94
109
  - ".rubocop.yml"
95
110
  - ".ruby-version"
111
+ - ".yardopts"
112
+ - Changelog.md
96
113
  - Gemfile
97
114
  - Guardfile
98
115
  - LICENSE
@@ -217,3 +234,4 @@ test_files:
217
234
  - spec/support/integration_macros.rb
218
235
  - spec/support/wordpress_server.rb
219
236
  - spec/tag_spec.rb
237
+ has_rdoc: