backlog-api 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem 'rake', '0.8.7'
10
+ gem "rspec", "~> 2.3.0"
11
+ gem "bundler", "~> 1.0.0"
12
+ gem "jeweler", "~> 1.6.2"
13
+ gem "rcov", ">= 0"
14
+ end
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 yoppi
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
1
+ # backlog-api
2
+ A library to Easy Access Backlog(http://www.backlog.jp) API from Ruby.
3
+
4
+ ## Installation
5
+ Ok, you just type
6
+
7
+ $ gem install backlog-api
8
+
9
+ ## How to use
10
+ First, create backlog client to accessing API.
11
+ Second, call API
12
+
13
+ require 'backlog-api'
14
+ backlog = Backlog::Client.new("space", "user", "password")
15
+ # get Project List
16
+ projects = backlog.get_projects()
17
+ # get Issue
18
+ issue = backlog.get_issue("issue_key")
19
+
20
+ ## Copyright
21
+ Copyright (c) 2011 yoppi. See LICENSE.txt for further details.
22
+
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "backlog-api"
18
+ gem.homepage = "http://github.com/yoppi/backlog-api"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Backlog API}
21
+ gem.description = %Q{A library to Access Backlog Issue from Ruby}
22
+ gem.email = "y.hirokazu@gmail.com"
23
+ gem.authors = ["yoppi"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+ require 'rake/rdoctask'
42
+ Rake::RDocTask.new do |rdoc|
43
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "backlog-api #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.0
@@ -0,0 +1,68 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{backlog-api}
8
+ s.version = "0.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = [%q{yoppi}]
12
+ s.date = %q{2011-10-09}
13
+ s.description = %q{A library to Access Backlog Issue from Ruby}
14
+ s.email = %q{y.hirokazu@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "LICENSE.txt",
24
+ "README.md",
25
+ "Rakefile",
26
+ "VERSION",
27
+ "backlog-api.gemspec",
28
+ "lib/backlog.rb",
29
+ "lib/backlog/api.rb",
30
+ "lib/backlog/client.rb",
31
+ "lib/backlog/object.rb",
32
+ "spec/backlog/api_spec.rb",
33
+ "spec/backlog/client_spec.rb",
34
+ "spec/backlog/object_spec.rb",
35
+ "spec/backlog_spec.rb",
36
+ "spec/spec_helper.rb"
37
+ ]
38
+ s.homepage = %q{http://github.com/yoppi/backlog-api}
39
+ s.licenses = [%q{MIT}]
40
+ s.require_paths = [%q{lib}]
41
+ s.rubygems_version = %q{1.8.7}
42
+ s.summary = %q{Backlog API}
43
+
44
+ if s.respond_to? :specification_version then
45
+ s.specification_version = 3
46
+
47
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
48
+ s.add_development_dependency(%q<rake>, ["= 0.8.7"])
49
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
50
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
51
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.2"])
52
+ s.add_development_dependency(%q<rcov>, [">= 0"])
53
+ else
54
+ s.add_dependency(%q<rake>, ["= 0.8.7"])
55
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
56
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
57
+ s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
58
+ s.add_dependency(%q<rcov>, [">= 0"])
59
+ end
60
+ else
61
+ s.add_dependency(%q<rake>, ["= 0.8.7"])
62
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
63
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
64
+ s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
65
+ s.add_dependency(%q<rcov>, [">= 0"])
66
+ end
67
+ end
68
+
@@ -0,0 +1,9 @@
1
+ # coding: utf-8
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__))
4
+
5
+ module Backlog
6
+ require 'backlog/api'
7
+ require 'backlog/object'
8
+ require 'backlog/client'
9
+ end
@@ -0,0 +1,132 @@
1
+ # coding: utf-8
2
+
3
+ module Backlog
4
+ module API
5
+ class ArgumentError < StandardError ; end
6
+
7
+ def get_projects
8
+ self.call("backlog.getProjects").map {|project|
9
+ Backlog::Object::Project.new(project)
10
+ }
11
+ end
12
+
13
+ # String | Integer -> Backlog::Object::Project
14
+ def get_project(project_key)
15
+ Backlog::Object::Project.new(
16
+ self.call("backlog.getProject", conv_str_to_int(project_key))
17
+ )
18
+ end
19
+
20
+ def get_components(project_id)
21
+ self.call("backlog.getComponents", project_id).map {|component|
22
+ Backlog::Object::Component.new(component)
23
+ }
24
+ end
25
+
26
+ def get_versions(project_id)
27
+ self.call("backlog.getVersions", project_id).map {|version|
28
+ Backlog::Object::Version.new(version)
29
+ }
30
+ end
31
+
32
+ def get_users(project_id)
33
+ self.call("backlog.getUsers", project_id).map {|user|
34
+ Backlog::Object::User.new(user)
35
+ }
36
+ end
37
+
38
+ # String | Integer -> Backlog::Object::DetailUser
39
+ def get_user(user_key)
40
+ Backlog::Object::DetailUser.new(
41
+ self.call("backlog.getUser", conv_str_to_int(user_key))
42
+ )
43
+ end
44
+
45
+ # String | Integer -> Backlog::Object::UserIcon
46
+ def get_user_icon(user_key)
47
+ Backlog::Object::UserIcon.new(
48
+ self.call("backlog.getUserIcon", conv_str_to_int(user_key))
49
+ )
50
+ end
51
+
52
+ def get_issue_types(project_id)
53
+ self.call("backlog.getIssueTypes", project_id).map {|issue_type|
54
+ Backlog::Object::IssueType.new(issue_type)
55
+ }
56
+ end
57
+
58
+ # String | Integer -> Backlog::Object::Issue
59
+ def get_issue(issue_key)
60
+ Backlog::Object::Issue.new(
61
+ self.call("backlog.getIssue", conv_str_to_int(issue_key))
62
+ )
63
+ end
64
+
65
+ def get_comments(issue_id)
66
+ self.call("backlog.getComments", issue_id).map {|comment|
67
+ Backlog::Object::Comment.new(comment)
68
+ }
69
+ end
70
+
71
+ def get_timeline
72
+ self.call("backlog.getTimeline").map {|timeline|
73
+ Backlog::Object::Timeline.new(timeline)
74
+ }
75
+ end
76
+
77
+ def get_activity_types
78
+ self.call("backlog.getActivityTypes").map {|activity_type|
79
+ Backlog::Object::ActivityType.new(activity_type)
80
+ }
81
+ end
82
+
83
+ def get_statuses
84
+ self.call("backlog.getStatuses").map {|status|
85
+ Backlog::Object::Status.new(status)
86
+ }
87
+ end
88
+
89
+ def get_resolutions
90
+ self.call("backlog.getResolutions").map {|resolution|
91
+ Backlog::Object::Resolution.new(resolution)
92
+ }
93
+ end
94
+
95
+ def get_priorities
96
+ self.call("backlog.getPriorities").map {|priority|
97
+ Backlog::Object::Priority.new(priority)
98
+ }
99
+ end
100
+
101
+ # Integer -> (String|Integer) -> Backlog::Object::CustomFields
102
+ def get_custom_fields(project_id, issue_type=nil)
103
+ h = {"project_id" => project_id}
104
+ if issue_type.instance_of? String
105
+ h["issue_type"] = issue_type
106
+ elsif issue_type.instance_of? Integer
107
+ h["issue_type_id"] = isuissue_type
108
+ end
109
+ self.call("backlog.getCustomFields", h).map {|custom_field|
110
+ Backlog::Object::CustomField.new(custom_field)
111
+ }
112
+ end
113
+
114
+ # Hash -> Integer
115
+ def count_issue(condition)
116
+ raise Backlog::API::ArgumentError, "must specify 'projectId'" unless condition.has_key? "projectId"
117
+ condition = Backlog::Object::FindCondition.new(condition)
118
+ self.call("backlog.countIssue", condition.to_h)
119
+ end
120
+
121
+ # String(Integer) -> Integer
122
+ # String(String) -> String
123
+ # Integer -> Integer
124
+ def conv_str_to_int(x)
125
+ if x.instance_of? String
126
+ (x.to_i.zero? && x != "0") ? x : x.to_i
127
+ else
128
+ x
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+
3
+ require 'xmlrpc/client'
4
+
5
+ module Backlog
6
+ class Client
7
+ include API
8
+
9
+ BACKLOG_API = "https://%s:%s@%s.backlog.jp/XML-RPC"
10
+
11
+ def initialize(space, username, password)
12
+ @space = space
13
+ @username = username
14
+ @password = password
15
+ @client = XMLRPC::Client.new2(BACKLOG_API % [@username, @password, @space])
16
+ end
17
+ attr_reader :space, :username, :password, :client
18
+
19
+ def call(method, args=nil)
20
+ if args
21
+ @client.call(method, args)
22
+ else
23
+ @client.call(method)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,247 @@
1
+ # coding: utf-8
2
+
3
+ module Backlog
4
+ module Object
5
+ class Serializable
6
+ def to_h
7
+ self.instance_variables.inject({}) {|ret, v|
8
+ ret[v.to_s.gsub(/^@/, '')] = self.instance_variable_get(v.to_s)
9
+ ret
10
+ }
11
+ end
12
+ end
13
+
14
+ class Project
15
+ def initialize(project)
16
+ @id = project['id']
17
+ @name = project['name']
18
+ @key = project['key']
19
+ @url = project['url']
20
+ @archived = project['archived']
21
+ end
22
+ attr_reader :id, :name, :key, :url, :archived
23
+ end
24
+
25
+ class Component
26
+ def initialize(component)
27
+ @id = component['id']
28
+ @name = component['name']
29
+ end
30
+ attr_reader :id, :name
31
+ end
32
+
33
+ class Version
34
+ def initialize(version)
35
+ @id = version['id']
36
+ @name = version['name']
37
+ @date = version['date']
38
+ end
39
+ attr_reader :id, :name, :date
40
+ end
41
+
42
+ class User
43
+ def initialize(user)
44
+ @id = user['id']
45
+ @name = user['name']
46
+ end
47
+ attr_reader :id, :name
48
+ end
49
+
50
+ class DetailUser < User
51
+ def initialize(user)
52
+ super(user)
53
+ @lang = user['lang']
54
+ @updated_on = user['updated_on']
55
+ end
56
+ attr_reader :lang, :updated_on
57
+ end
58
+
59
+ class UserIcon
60
+ def initialize(user_icon)
61
+ @id = user_icon['id']
62
+ @content_type = user_icon['content_type']
63
+ # backlog.getUserIcon['data'] isn't encoded, so encode here.
64
+ @data = XMLRPC::Base64.encode(user_icon['data']).delete("\n")
65
+ @updated_on = user_icon['updated_on']
66
+ end
67
+ attr_reader :id, :content_type, :data, :updated_on
68
+ end
69
+
70
+ class IssueType
71
+ def initialize(issue_type)
72
+ @id = issue_type['id']
73
+ @name = issue_type['name']
74
+ @color = issue_type['color']
75
+ end
76
+ attr_reader :id, :name, :color
77
+ end
78
+
79
+ class Issue
80
+ def initialize(issue)
81
+ @id = issue['id']
82
+ @key = issue['key']
83
+ @summary = issue['summary']
84
+ @description = issue['description']
85
+ @url = issue['url']
86
+ @due_date = issue['due_date']
87
+ @start_date = issue['start_date'],
88
+ @estimated_hours = issue['estimated_hours']
89
+ @actual_hours = issue['actual_hours']
90
+ @issue_type = issue['issue_type'] ? IssueType.new(issue['issue_type']) : nil
91
+ @priority = issue['priority'] ? Priority.new(issue['priority']) : nil
92
+ @resolution = issue['resolution'] ? Resolution.new(issue['resolution']) : nil
93
+ @status = issue['status'] ? Status.new(issue['status']) : nil
94
+ @components = issue['components'] ? issue['components'].map {|x| Component.new(x) } : []
95
+ @versions = issue['versions'] ? issue['versions'].map {|x| Version.new(x) } : []
96
+ @milestones = issue['milestone'] ? issue['milestones'].map {|x| Milestone.new(x)} : []
97
+ @created_user = issue['created_user'] ? User.new(issue['created_user']) : nil
98
+ @assigner = issue['assigner'] ? User.new(issue['assigner']) : nil
99
+ @created_on = issue['created_on']
100
+ @updated_on = issue['updated_on']
101
+ @custom_fields = issue['custom_fields']
102
+ end
103
+ attr_reader :id, :key, :summary, :description, :url,
104
+ :due_date, :start_date, :estimated_hours,
105
+ :actual_hours, :issue_type, :priority,
106
+ :resolution, :status, :components, :versions,
107
+ :milestones, :created_user, :assigner,
108
+ :created_on, :updated_on, :custom_fields
109
+ end
110
+
111
+ class Priority
112
+ def initialize(priority)
113
+ @id = priority['id']
114
+ @name = priority['name']
115
+ end
116
+ attr_reader :id, :name
117
+ end
118
+
119
+ class Resolution
120
+ def initialize(resolution)
121
+ @id = resolution['id']
122
+ @name = resolution['name']
123
+ end
124
+ attr_reader :id, :name
125
+ end
126
+
127
+ class Status
128
+ def initialize(status)
129
+ @id = status['id']
130
+ @name = status['name']
131
+ end
132
+ attr_reader :id, :name
133
+ end
134
+
135
+ class Item
136
+ def initialize(item)
137
+ @id = item['id']
138
+ @name = item['name']
139
+ end
140
+ end
141
+
142
+ class Milestone
143
+ def initialize(milestone)
144
+ @id = milestone['id']
145
+ @name = milestone['name']
146
+ @date = milestone['date']
147
+ end
148
+ attr_reader :id, :name, :date
149
+ end
150
+
151
+ class Comment
152
+ def initialize(comment)
153
+ @id = comment['id']
154
+ @content = comment['content']
155
+ @created_user = User.new(comment['created_user'])
156
+ @created_on = comment['created_on']
157
+ @updated_on = comment['updated_on']
158
+ end
159
+ attr_reader :id, :content, :created_user, :created_on, :updated_on
160
+ end
161
+
162
+ class Timeline
163
+ def initialize(timeline)
164
+ @type = timeline['type'] ? ActivityType.new(timeline['type']) : nil
165
+ @content = timeline['content']
166
+ @updated_on = timeline['updated_on']
167
+ @user = timeline['user'] ? User.new(timeline['user']) : nil
168
+ @issue = timeline['issue'] ? Issue.new(timeline['issue']) : nil
169
+ end
170
+ attr_reader :type, :content, :updated_on, :user, :issue
171
+ end
172
+
173
+ class ActivityType
174
+ def initialize(activity_type)
175
+ @id = activity_type['id']
176
+ @name = activity_type['name']
177
+ end
178
+ attr_reader :id, :name
179
+ end
180
+
181
+ class CustomField
182
+ def initialize(custom_field)
183
+ @id = custom_field['id']
184
+ @type_id = custom_field['type_id']
185
+ @name = custom_field['name']
186
+ @description = custom_field['description']
187
+ @required = custom_field['required']
188
+ if custom_field['issue_types']
189
+ @issue_types = custom_field['issue_types'].map {|issue_type| IssueType.new(issue_type) }
190
+ end
191
+ # custom_field type is Number(type_id = 3)
192
+ @min = custom_field['min']
193
+ @max = custom_field['max']
194
+ @initial_value = custom_field['initial_value']
195
+ @unit = custom_field['unit']
196
+ # custom_field type is Date(type_id = 4)
197
+ @initial_value_type = custom_field['initial_value_type']
198
+ @initial_shift = custom_field['initial_shift']
199
+ @initial_date = custom_field['initial_date']
200
+ # custom_field type is List(type_id = 5,6)
201
+ if custom_field['items']
202
+ @items = custom_field['items'].map {|item| Item.new(item)}
203
+ end
204
+ # custom_field type is CheckBox or RadioButton(type_id = 7,8)
205
+ @allow_input = custom_field['allow_input']
206
+ end
207
+ attr_reader :id, :type_id, :name, :description, :required,
208
+ :issue_types,
209
+ :min, :max, :initial_value, :unit,
210
+ :initial_value_type, :initial_shift, :initial_date,
211
+ :items,
212
+ :allow_input
213
+ end
214
+
215
+ class FindCondition < Serializable
216
+ CONDITION_KEYS = %w[
217
+ projectId
218
+ issueTypeId
219
+ issueType
220
+ componentId
221
+ versionId
222
+ milestoneId
223
+ statusId
224
+ priorityId
225
+ assignerId
226
+ createdUserId
227
+ resolutionId
228
+ created_on_min
229
+ created_on_max
230
+ updated_on_min
231
+ updated_on_max
232
+ ].each {|k|
233
+ class_eval { attr_reader k.to_sym }
234
+ }
235
+
236
+ def initialize(condition)
237
+ condition.each {|k, v|
238
+ self.instance_eval %Q{
239
+ if CONDITION_KEYS.include? k
240
+ @#{k} = v
241
+ end
242
+ }
243
+ }
244
+ end
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,519 @@
1
+ # coding: utf-8
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
4
+
5
+ describe Backlog::API do
6
+ before(:each) do
7
+ @client = Backlog::Client.new("hoge", "yoppi", "test")
8
+ end
9
+
10
+ describe "プロジェクトAPI" do
11
+ context "プロジェクトの一覧を取得する" do
12
+ let(:projects) {
13
+ [{"id" => 100,
14
+ "name" => "test",
15
+ "key" => "TEST",
16
+ "url" => "http://hoge.backlog.jp/TEST",
17
+ "archived" => false}]
18
+ }
19
+
20
+ before do
21
+ mock(@client).call.with_any_args { projects }
22
+ end
23
+
24
+ it "プロジェクトのリストを取得できる" do
25
+ @client.get_projects.class.should == Array
26
+ end
27
+ end
28
+
29
+ context "プロジェクトを取得する" do
30
+ let(:project) {
31
+ {"id" => 100,
32
+ "name" => "test",
33
+ "key" => "TEST",
34
+ "url" => "http://hoge.backlog.jp/TEST",
35
+ "archived" => false}
36
+ }
37
+
38
+ before do
39
+ mock(@client).call.with_any_args { project }
40
+ end
41
+
42
+ it "project_idを指定してプロジェクトを取得できる" do
43
+ @client.get_project(100).class.should == Backlog::Object::Project
44
+ end
45
+
46
+ it "keyを指定してプロジェクトを取得できる" do
47
+ @client.get_project("key").class.should == Backlog::Object::Project
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "カテゴリAPI" do
53
+ context "プロジェクトのカテゴリを取得する" do
54
+ let(:component) {
55
+ [{"id" => 100,
56
+ "name" => "カテゴリ名"}]
57
+ }
58
+
59
+ before do
60
+ mock(@client).call.with_any_args { component }
61
+ end
62
+
63
+ it "指定したプロジェクトのカテゴリが取得できる" do
64
+ @client.get_components(100).class.should == Array
65
+ end
66
+
67
+ it "取得したカテゴリはすべてカテゴリオブジェクトである" do
68
+ @client.get_components(100).each {|component|
69
+ component.class.should == Backlog::Object::Component
70
+ }
71
+ end
72
+ end
73
+ end
74
+
75
+ describe "バージョンAPI" do
76
+ context "プロジェクトの発生バージョン/マイルストーンを取得する" do
77
+ let(:version) {
78
+ [{"id" => 733,
79
+ "name" => "サイトオープン",
80
+ "date" => "20110808"}]
81
+ }
82
+
83
+ before do
84
+ mock(@client).call.with_any_args { version }
85
+ end
86
+
87
+ it "プロジェクトを指定して発生バージョンが取得できる" do
88
+ @client.get_versions(100).class.should == Array
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "ユーザAPI" do
94
+ context "プロジェクトの参加メンバーを取得する" do
95
+ let(:user) {
96
+ [{"id" => 1000,
97
+ "name" => "yoppi"}]
98
+ }
99
+
100
+ before do
101
+ mock(@client).call.with_any_args{ user }
102
+ end
103
+
104
+ it "プロジェクトを指定してその参加メンバーを取得できる" do
105
+ @client.get_users(100).class.should == Array
106
+ end
107
+ end
108
+
109
+ context "特定のユーザの情報を取得する" do
110
+ let(:user) {
111
+ {"id" => 1000,
112
+ "name" => "yoppi",
113
+ "lang" => "ja",
114
+ "updated_on" => "20110807220000"}
115
+ }
116
+
117
+ before do
118
+ mock(@client).call.with_any_args { user }
119
+ end
120
+
121
+ it "ユーザIDを指定してそのユーザの情報を取得する" do
122
+ @client.get_user(100).class.should == Backlog::Object::DetailUser
123
+ end
124
+ end
125
+
126
+ context "特定のユーザのアイコンを取得する" do
127
+ let(:user_icon) {
128
+ {
129
+ "id" => 1000,
130
+ "content_type" => "image/gif",
131
+ "data" => "/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDMvWNpEHL5ycCo00rV7+NZrOylkjI+WR2VB+GeTVhGjQj7UHlfP7uN+Ax/Ht7f4VPa+OjoupS2GrSRb5pEaKOINiFWHG7PUng8V51SpKWkS8Jg4RSnUMqa11OwkEd9ZmPJwr5DZP1FNMUjA5P4cf4VtJd6rHbyQa1HBcRnMnnRMeUyTg579uPSqTPAw2wENH2yBkd8E06NR35WZ47CRSdSI3QbG28NXD3K3VzdyyZUxTMNiruU9upwDzx19zXPa3px1DxAuoopQZU5LZ6etd/d2EUwIkwy9RkYwayZrRg4KuVRei8VsoPmuc7xb5bET6hBLZGOVH85YNkc0e5eSSWDAHG0/J2zwazrJVt1IjiOPUD7x/OtG437CAcA8deRTYLWadRicmNONoAGP0qPZ8slYcq7qQfMf//Z",
132
+ }
133
+ }
134
+
135
+ before do
136
+ mock(@client).call.with_any_args { user_icon }
137
+ end
138
+
139
+ it "ユーザを指定してそのユーザのアイコンが取得できる" do
140
+ @client.get_user_icon(100).class.should == Backlog::Object::UserIcon
141
+ end
142
+ end
143
+ end
144
+
145
+ describe "イシューAPI" do
146
+ context "プロジェクトのイシュータイプを取得する" do
147
+ let(:issue_types) {
148
+ [{"id" => 2000,
149
+ "name" => "タスク",
150
+ "color" => "#7ea800"
151
+ }]
152
+ }
153
+
154
+ before do
155
+ mock(@client).call.with_any_args { issue_types }
156
+ end
157
+
158
+ it "プロジェクトを指定してそのイシュータイプのリストを取得する" do
159
+ @client.get_issue_types(100).class.should == Array
160
+ end
161
+
162
+ it "イシュータイプのリスト要素はすべてイシュータイプオブジェクトである" do
163
+ @client.get_issue_types(100).each {|issue_type|
164
+ issue_type.class.should == Backlog::Object::IssueType
165
+ }
166
+ end
167
+ end
168
+
169
+ context "プロジェクトのイシューを取得する" do
170
+ let(:issue) {
171
+ {
172
+ "id" => 1617103,
173
+ "key" => "ISSUE-100",
174
+ "summary" => "トップページのデザイン決定",
175
+ "description" => "トップページのデザイン決定する",
176
+ "url" => "https://test.backog.jp/view/ISSUE-100",
177
+ "due_date" => "20110831",
178
+ "start_date" => "20110720",
179
+ "estimated_hours" => "100",
180
+ "actual_hours" => "200",
181
+ "issue_type" => {"id" => 2000,
182
+ "name" => "タスク",
183
+ "color" => "#7ea800"},
184
+ "priority" => {"id" => 300, "name" => "中"},
185
+ "resolution" => {"id" => 400, "name" => "対応済み"},
186
+ "status" => {"id" => 2, "name" => "処理中"},
187
+ "components" => [{"id" => 100,
188
+ "name" => "カテゴリ名"}],
189
+ "versions" => [{"id" => 733,
190
+ "name" => "サイトオープン",
191
+ "date" => "20110808"}],
192
+ "milestones" => [{"id" => 800,
193
+ "name" => "8/21リリース",
194
+ "date" => "20110821"}],
195
+ "created_user" => {"id" => 1000, "name" => "yoppi"},
196
+ "assigner" => {"id" => 1000, "name" => "yoppi"},
197
+ "created_on" => "20110701",
198
+ "updated_on" => "20110807",
199
+ "custom_fields" => []
200
+ }
201
+ }
202
+
203
+ before do
204
+ mock(@client).call.with_any_args { issue }
205
+ end
206
+
207
+ it "課題キーを指定してイシューを取得できる" do
208
+ @client.get_issue("ISSUE-100").class.should == Backlog::Object::Issue
209
+ end
210
+ end
211
+ end
212
+
213
+ describe "コメントAPI" do
214
+ context "イシューのコメントを取得する" do
215
+ let(:comments) {
216
+ [{"id" => "12889281",
217
+ "content" => "ここはもっとシンプルなデザインがいいと思いました。",
218
+ "created_user" => {"id" => 100, "name" => "yoppi"},
219
+ "created_on" => "20110808165300",
220
+ "updated_on" => "20110808165300"
221
+ }]
222
+ }
223
+
224
+ before do
225
+ mock(@client).call.with_any_args { comments }
226
+ end
227
+
228
+ it "指定したイシューのコメントが取得できる" do
229
+ @client.get_comments(1000).class.should == Array
230
+ end
231
+ end
232
+ end
233
+
234
+ describe "タイムラインAPI" do
235
+ context "タイムライン(イシューの更新情報)の一覧を取得する" do
236
+ let(:timeline) {
237
+ [{
238
+ "type" => {"id" => 1, "name" => "更新"},
239
+ "content" => "着手しました",
240
+ "updated_on" => "20110807194600",
241
+ "user" => {"id" => 100, "name" => "yoppi"},
242
+ "issue" => {"id" => "73", "key" => "ISSUE-100",
243
+ "summary" => "トップページのデザイン決定",
244
+ "description" => "トップページのデザイン決定します",
245
+ "priority" => {"id" => 2, "name" => "中"}}
246
+ }]
247
+ }
248
+
249
+ before do
250
+ mock(@client).call.with_any_args { timeline }
251
+ end
252
+
253
+ it "タイムラインの一覧が取得できる" do
254
+ @client.get_timeline().class.should == Array
255
+ end
256
+ end
257
+ end
258
+
259
+ describe "イシューの更新情報の種別一覧API" do
260
+ let(:activity_types) {
261
+ [
262
+ {"id" => 100,
263
+ "name" => "課題"}
264
+ ]
265
+ }
266
+
267
+ before do
268
+ mock(@client).call.with_any_args { activity_types }
269
+ end
270
+
271
+ it "イシューの更新情報の種別一覧を取得できる" do
272
+ @client.get_activity_types().class.should == Array
273
+ end
274
+
275
+ it "各種別のオブジェクトであること" do
276
+ @client.get_activity_types().each {|activity_type|
277
+ activity_type.class.should == Backlog::Object::ActivityType
278
+ }
279
+ end
280
+ end
281
+
282
+ describe "イシュー状態API" do
283
+ let(:statuses) {
284
+ [{"id" => 4, "name" => "完了"}]
285
+ }
286
+
287
+ before do
288
+ mock(@client).call.with_any_args { statuses }
289
+ end
290
+
291
+ it "イシューの状態一覧を取得できる" do
292
+ @client.get_statuses().class.should == Array
293
+ end
294
+
295
+ it "取得したイシューの状態一覧の各状態はStatusオブジェクトであること" do
296
+ @client.get_statuses().each {|status|
297
+ status.class.should == Backlog::Object::Status
298
+ }
299
+ end
300
+ end
301
+
302
+ describe "イシュー完了理由API" do
303
+ let(:resolutions) {
304
+ [{"id" => 0, "name" => "対応済み"}]
305
+ }
306
+
307
+ before do
308
+ mock(@client).call.with_any_args { resolutions }
309
+ end
310
+
311
+ it "イシューの完了理由一覧を取得できる" do
312
+ @client.get_resolutions().class.should == Array
313
+ end
314
+
315
+ it "取得したイシューの完了理由一覧はResolutionオブジェクトであること" do
316
+ @client.get_resolutions().each {|resolution|
317
+ resolution.class.should == Backlog::Object::Resolution
318
+ }
319
+ end
320
+ end
321
+
322
+ describe "イシューの優先度一覧取得API" do
323
+ let(:priorities) {
324
+ [{"id" => 3, "name" => "中"}]
325
+ }
326
+
327
+ before do
328
+ mock(@client).call.with_any_args { priorities }
329
+ end
330
+
331
+ it "イシューの優先度一覧を取得できる" do
332
+ @client.get_priorities().class.should == Array
333
+ end
334
+
335
+ it "取得したイシューの各優先度はPriorityオブジェクトであること" do
336
+ @client.get_priorities().each {|priority|
337
+ priority.class.should == Backlog::Object::Priority
338
+ }
339
+ end
340
+ end
341
+
342
+ describe "カスタム属性の情報取得API" do
343
+ context "カスタム属性タイプが文字列の場合" do
344
+ let(:custom_fields_1) {
345
+ [{"id" => 4,
346
+ "type_id" => 1,
347
+ "name" => "OS",
348
+ "description" => "現象が発生したOS",
349
+ "required" => 1,
350
+ "issue_types" => [{"id" => 5, "name" => "バグ", "color" => "#990000"}]}]
351
+ }
352
+
353
+ before do
354
+ mock(@client).call.with_any_args { custom_fields_1 }
355
+ end
356
+
357
+ it "プロジェクトIDを指定して登録しているカスタム属性の情報を取得できる" do
358
+ @client.get_custom_fields(100).class.should == Array
359
+ end
360
+
361
+ it "プロジェクトIDをissue_type_idを指定して登録しているカスタム属性の情報を取得できる" do
362
+ @client.get_custom_fields(100, 10).class.should == Array
363
+ end
364
+
365
+ it "プロジェクトIDをissue_typeを指定して登録しているカスタム属性の情報を取得できる" do
366
+ @client.get_custom_fields(100, "バグ").class.should == Array
367
+ end
368
+
369
+ it "取得したカスタム属性情報はCustomFieldsオブジェクトであること" do
370
+ @client.get_custom_fields(100).each {|custom_field|
371
+ custom_field.class.should == Backlog::Object::CustomField
372
+ custom_field.id.should == custom_fields_1.first["id"]
373
+ custom_field.type_id.should == custom_fields_1.first["type_id"]
374
+ custom_field.name.should == custom_fields_1.first["name"]
375
+ custom_field.description.should == custom_fields_1.first["description"]
376
+ custom_field.required.should == custom_fields_1.first["required"]
377
+ custom_field.issue_types.class.should == Array
378
+ custom_field.issue_types.each {|issue_type|
379
+ issue_type.class.should == Backlog::Object::IssueType
380
+ issue_type.id.should == custom_fields_1.first["issue_types"].first["id"]
381
+ issue_type.name.should == custom_fields_1.first["issue_types"].first["name"]
382
+ issue_type.color.should == custom_fields_1.first["issue_types"].first["color"]
383
+ }
384
+ }
385
+ end
386
+ end
387
+
388
+ context "カスタム属性タイプが数値の場合" do
389
+ let(:custom_fields_3) {
390
+ [{"id" => 10,
391
+ "type_id" => 3,
392
+ "name" => "割合",
393
+ "description" => "発生した割合",
394
+ "required" => 1,
395
+ "issue_types" => [{"id" => 5, "name" => "バグ", "color" => "#990000"}],
396
+ "min" => 0.0,
397
+ "max" => 100.0,
398
+ "initial_value" => 0.0,
399
+ "unit" => "%"
400
+ }]
401
+ }
402
+
403
+ before do
404
+ mock(@client).call.with_any_args { custom_fields_3 }
405
+ end
406
+
407
+ it "取得したカスタム属性情報はCustomFieldオブジェクトであること" do
408
+ @client.get_custom_fields(100).each {|custom_field|
409
+ custom_field.min.should == custom_fields_3.first["min"]
410
+ custom_field.max.should == custom_fields_3.first["max"]
411
+ custom_field.initial_value.should == custom_fields_3.first["initial_value"]
412
+ custom_field.unit.should == custom_fields_3.first["unit"]
413
+ }
414
+ end
415
+ end
416
+
417
+ context "カスタム属性タイプが日付の場合" do
418
+ let(:custom_fields_4) {
419
+ [{"id" => 20,
420
+ "type_id" => 4,
421
+ "name" => "日付",
422
+ "description" => "発生した日付",
423
+ "required" => 1,
424
+ "issue_types" => [{"id" => 5, "name" => "バグ", "color" => "#990000"}],
425
+ "initial_value_type" => 1,
426
+ "min" => 100.0,
427
+ "max" => 0.0,
428
+ }]
429
+ }
430
+
431
+ before do
432
+ mock(@client).call.with_any_args { custom_fields_4 }
433
+ end
434
+
435
+ it "取得したカスタム属性情報はCustomFieldオブジェクトであること" do
436
+ @client.get_custom_fields(100).each {|custom_field|
437
+ custom_field.initial_value_type.should == custom_fields_4.first["initial_value_type"]
438
+ custom_field.min.should == custom_fields_4.first["min"]
439
+ custom_field.max.should == custom_fields_4.first["max"]
440
+ }
441
+ end
442
+ end
443
+
444
+ context "カスタム属性タイプがリストの場合" do
445
+ let(:custom_fields_5) {
446
+ [{"id" => 20,
447
+ "type_id" => 5,
448
+ "name" => "OS",
449
+ "description" => "発生したOS",
450
+ "required" => 1,
451
+ "issue_types" => [{"id" => 5, "name" => "バグ", "color" => "#990000"}],
452
+ "items" => [{"id" => 1, "name" => "windows"}]
453
+ }]
454
+ }
455
+
456
+ before do
457
+ mock(@client).call.with_any_args { custom_fields_5 }
458
+ end
459
+
460
+ it "取得したカスタム属性情報はCustomFieldオブジェクトであること" do
461
+ @client.get_custom_fields(100).each {|custom_field|
462
+ custom_field.items.class == Array
463
+ custom_field.items.each {|item|
464
+ item.class.should == Backlog::Object::Item
465
+ }
466
+ }
467
+ end
468
+ end
469
+
470
+ context "カスタム属性タイプがチェックボックスの場合" do
471
+ let(:custom_fields_7) {
472
+ [{"id" => 20,
473
+ "type_id" => 5,
474
+ "name" => "OS",
475
+ "description" => "発生したOS",
476
+ "required" => 1,
477
+ "issue_types" => [{"id" => 5, "name" => "バグ", "color" => "#990000"}],
478
+ "allow_input" => "1",
479
+ "items" => [{"id" => 1, "name" => "windows"}]
480
+ }]
481
+ }
482
+
483
+ before do
484
+ mock(@client).call.with_any_args { custom_fields_7 }
485
+ end
486
+
487
+ it "取得したカスタム属性情報はCustomFieldオブジェクトであること" do
488
+ @client.get_custom_fields(100).each {|custom_field|
489
+ custom_field.allow_input.should == custom_fields_7.first['allow_input']
490
+ }
491
+ end
492
+ end
493
+ end
494
+
495
+ describe "イシュー件数検索API" do
496
+ context "クエリにproject_idがない場合" do
497
+ let(:condition) {
498
+ {"issueTypeId" => 100}
499
+ }
500
+ it "例外が発生する" do
501
+ expect { @client.count_issue(condition) }.should raise_error(Backlog::API::ArgumentError)
502
+ end
503
+ end
504
+ context "指定した検索条件で検索する" do
505
+ let(:condition) {
506
+ {
507
+ "projectId" => 100,
508
+ "issueTypeId" => 10
509
+ }
510
+ }
511
+ before do
512
+ mock(@client).call.with_any_args { 1 }
513
+ end
514
+ it "指定した検索条件で検索できる" do
515
+ @client.count_issue(condition).should == 1
516
+ end
517
+ end
518
+ end
519
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
4
+
5
+ describe Backlog::Client do
6
+ context "特定のユーザのプロジェクトでAPIにアクセスする" do
7
+ let(:space) { 'test' }
8
+ let(:username) { 'yoppi' }
9
+ let(:password) { 'hoge' }
10
+ let(:client) {
11
+ Backlog::Client.new(space, username, password)
12
+ }
13
+
14
+ it "Backlogにアクセスするクライアントオブジェクトが生成されること" do
15
+ client.should_not be_nil
16
+ end
17
+
18
+ it "ユーザ名が取得できること" do
19
+ client.username.should == username
20
+ end
21
+
22
+ it "スペース名が取得できること" do
23
+ client.space.should == space
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
4
+
5
+ describe Backlog::Object::FindCondition do
6
+ let(:params) {
7
+ {
8
+ "projectId" => 100,
9
+ "issueTypeId" => 10
10
+ }
11
+ }
12
+ it "指定したHashのパラメータが登録されていること" do
13
+ o = Backlog::Object::FindCondition.new(params)
14
+ o.projectId.should == params["projectId"]
15
+ o.issueTypeId.should == params["issueTypeId"]
16
+ end
17
+ it "Hashに変換できること" do
18
+ h = Backlog::Object::FindCondition.new(params).to_h
19
+ h["projectId"].should == params["projectId"]
20
+ h["issueTypeId"].should == params["issueTypeId"]
21
+ end
22
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Backlog" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $:.unshift(File.dirname(__FILE__))
3
+
4
+ require 'rspec'
5
+ require 'rr'
6
+ require 'pry'
7
+
8
+ require 'backlog'
9
+
10
+ # Requires supporting files with custom matchers and macros, etc,
11
+ # in ./support/ and its subdirectories.
12
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
13
+
14
+ RSpec.configure do |config|
15
+ config.mock_with :rr
16
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: backlog-api
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.0
6
+ platform: ruby
7
+ authors:
8
+ - yoppi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-10-09 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rake
17
+ requirement: &id001 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - "="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.8.7
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: &id002 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 2.3.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: bundler
39
+ requirement: &id003 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 1.0.0
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *id003
48
+ - !ruby/object:Gem::Dependency
49
+ name: jeweler
50
+ requirement: &id004 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: 1.6.2
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *id004
59
+ - !ruby/object:Gem::Dependency
60
+ name: rcov
61
+ requirement: &id005 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *id005
70
+ description: A library to Access Backlog Issue from Ruby
71
+ email: y.hirokazu@gmail.com
72
+ executables: []
73
+
74
+ extensions: []
75
+
76
+ extra_rdoc_files:
77
+ - LICENSE.txt
78
+ - README.md
79
+ files:
80
+ - .document
81
+ - .rspec
82
+ - Gemfile
83
+ - LICENSE.txt
84
+ - README.md
85
+ - Rakefile
86
+ - VERSION
87
+ - backlog-api.gemspec
88
+ - lib/backlog.rb
89
+ - lib/backlog/api.rb
90
+ - lib/backlog/client.rb
91
+ - lib/backlog/object.rb
92
+ - spec/backlog/api_spec.rb
93
+ - spec/backlog/client_spec.rb
94
+ - spec/backlog/object_spec.rb
95
+ - spec/backlog_spec.rb
96
+ - spec/spec_helper.rb
97
+ homepage: http://github.com/yoppi/backlog-api
98
+ licenses:
99
+ - MIT
100
+ post_install_message:
101
+ rdoc_options: []
102
+
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ hash: -1065371427
111
+ segments:
112
+ - 0
113
+ version: "0"
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: "0"
120
+ requirements: []
121
+
122
+ rubyforge_project:
123
+ rubygems_version: 1.8.7
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: Backlog API
127
+ test_files: []
128
+