backlog-api 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+