fcoury-octopi 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -28,6 +28,7 @@ Octopi is a Ruby interface to GitHub API v2 (http://develop.github.com). It's un
28
28
  # to get all repos for user: user.repositories
29
29
  repo = user.repository("octopi") # same as: Repository.find("fcoury", "octopi")
30
30
  puts "Repository: #{repo.name} - #{repo.description} (by #{repo.owner}) - #{repo.url}"
31
+ puts " Tags: #{repo.tags and repo.tags.map {|t| t.name}.join(", ")}"
31
32
 
32
33
  # commits of a the repository
33
34
  first_commit = repo.commits.first
@@ -47,8 +48,8 @@ Octopi is a Ruby interface to GitHub API v2 (http://develop.github.com). It's un
47
48
 
48
49
  == Author
49
50
 
50
- Felipe Coury - http://felipecoury.com<br/>
51
- HasMany.info blog - http://hasmany.info
51
+ * Felipe Coury - http://felipecoury.com
52
+ * HasMany.info blog - http://hasmany.info
52
53
 
53
54
  == Copyright
54
55
 
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :minor: 0
3
- :patch: 3
3
+ :patch: 4
4
4
  :major: 0
@@ -0,0 +1,32 @@
1
+ class Base
2
+ def initialize(api, hash)
3
+ @api = api
4
+ @keys = []
5
+
6
+ raise "Missing data for #{@resource}" unless hash
7
+
8
+ hash.each_pair do |k,v|
9
+ @keys << k
10
+ next if k =~ /\./
11
+ instance_variable_set("@#{k}", v)
12
+
13
+ self.class.send :define_method, "#{k}=" do |v|
14
+ instance_variable_set("@#{k}", v)
15
+ end
16
+
17
+ self.class.send :define_method, k do
18
+ instance_variable_get("@#{k}")
19
+ end
20
+ end
21
+ end
22
+
23
+ def property(p, v)
24
+ path = "#{self.class.path_for(:resource)}/#{p}"
25
+ @api.find(path, self.class.resource_name(:singular), v)
26
+ end
27
+ def save
28
+ hash = {}
29
+ @keys.each { |k| hash[k] = send(k) }
30
+ @api.save(self.path_for(:resource), hash)
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ module Octopi
2
+ class Blob < Base
3
+ include Resource
4
+ set_resource_name "blob"
5
+
6
+ resource_path "/blob/show/:id"
7
+
8
+ def self.find(user, repo, sha, path=nil)
9
+ user = user.login if user.is_a? User
10
+ repo = repo.name if repo.is_a? Repository
11
+ if path
12
+ super [user,repo,sha,path]
13
+ else
14
+ blob = ANONYMOUS_API.get_raw(path_for(:resource),
15
+ {:id => [user,repo,sha].join('/')})
16
+ new(ANONYMOUS_API, {:text => blob})
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,47 @@
1
+ module Octopi
2
+ class Commit < Base
3
+ include Resource
4
+ find_path "/commits/list/:query"
5
+ resource_path "/commits/show/:id"
6
+
7
+ attr_accessor :repository
8
+
9
+ def self.find_all(user, name, branch = "master", repo = nil)
10
+ repository = repo if repo.is_a? Repository
11
+ user = user.login if user.is_a? User
12
+ repo = repo.name if repo.is_a? Repository
13
+ name = repo.name if name.is_a? Repository
14
+ commits = super [user, name, branch]
15
+ commits.each { |c| c.repository = repository } if repository
16
+ commits
17
+ end
18
+
19
+ def self.find(*args)
20
+ if args.last.is_a?(Commit)
21
+ commit = args.pop
22
+ super "#{commit.repo_identifier}"
23
+ else
24
+ user, name, sha = *args
25
+ user = user.login if user.is_a? User
26
+ name = repo.name if name.is_a? Repository
27
+ super [user, name, sha]
28
+ end
29
+ end
30
+
31
+ def details
32
+ self.class.find(self)
33
+ end
34
+
35
+ def repo_identifier
36
+ url_parts = url.split('/')
37
+ if @repository
38
+ parts = [@repository.owner, @repository.name, url_parts[6]]
39
+ else
40
+ parts = [url_parts[3], url_parts[4], url_parts[6]]
41
+ end
42
+
43
+ puts parts.join('/')
44
+ parts.join('/')
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,14 @@
1
+ module Octopi
2
+ class FileObject < Base
3
+ include Resource
4
+ set_resource_name "tree"
5
+
6
+ resource_path "/tree/show/:id"
7
+
8
+ def self.find(user, repo, sha)
9
+ user = user.login if user.is_a? User
10
+ repo = repo.name if repo.is_a? Repository
11
+ super [user,repo,sha]
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,40 @@
1
+ module Octopi
2
+ class Repository < Base
3
+ include Resource
4
+ set_resource_name "repository", "repositories"
5
+
6
+ find_path "/repos/search/:query"
7
+ resource_path "/repos/show/:id"
8
+
9
+ def tags
10
+ Tag.find(self.owner, self.name)
11
+ end
12
+
13
+ def clone_url
14
+ #FIXME: Return "git@github.com:#{self.owner}/#{self.name}.git" if
15
+ #user's logged in and owns this repo.
16
+ "git://github.com/#{self.owner}/#{self.name}.git"
17
+ end
18
+
19
+ def self.find_by_user(user)
20
+ user = user.login if user.is_a? User
21
+ find_plural(user, :resource)
22
+ end
23
+
24
+ def self.find(user, name)
25
+ user = user.login if user.is_a? User
26
+ name = repo.name if name.is_a? Repository
27
+ super [user,name]
28
+ end
29
+
30
+ def self.find_all(*args)
31
+ # FIXME: This should be URI escaped, but have to check how the API
32
+ # handles escaped characters first.
33
+ super args.join(" ").gsub(/ /,'+')
34
+ end
35
+
36
+ def commits(branch = "master")
37
+ Commit.find_all(owner, name, branch, self)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,66 @@
1
+ module Octopi
2
+ module Resource
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.set_resource_name(base.name)
6
+ (@@resources||={})[base.resource_name(:singular)] = base
7
+ (@@resources||={})[base.resource_name(:plural)] = base
8
+ end
9
+
10
+ def self.for(name)
11
+ @@resources[name]
12
+ end
13
+
14
+ module ClassMethods
15
+ def set_resource_name(singular, plural = "#{singular}s")
16
+ @resource_name = {:singular => declassify(singular), :plural => declassify(plural)}
17
+ end
18
+
19
+ def resource_name(key)
20
+ @resource_name[key]
21
+ end
22
+
23
+ def declassify(s)
24
+ (s.split('::').last || '').downcase if s
25
+ end
26
+
27
+ def find_path(path)
28
+ (@path_spec||={})[:find] = path
29
+ end
30
+
31
+ def resource_path(path)
32
+ (@path_spec||={})[:resource] = path
33
+ end
34
+
35
+ def find(s)
36
+ s = s.join('/') if s.is_a? Array
37
+ result = ANONYMOUS_API.find(path_for(:resource), @resource_name[:singular], s)
38
+ key = result.keys.first
39
+ if result[key].is_a? Array
40
+ result[key].map do |r|
41
+ new(ANONYMOUS_API, r)
42
+ end
43
+ else
44
+ Resource.for(key).new(ANONYMOUS_API, result[key])
45
+ end
46
+ end
47
+
48
+ def find_all(s)
49
+ find_plural(s, :find)
50
+ end
51
+
52
+ def find_plural(s,path)
53
+ s = s.join('/') if s.is_a? Array
54
+ ANONYMOUS_API.find_all(path_for(path), @resource_name[:plural], s).
55
+ map do |item|
56
+ payload = block_given? ? yield(item) : item
57
+ new(ANONYMOUS_API, payload)
58
+ end
59
+ end
60
+
61
+ def path_for(type)
62
+ @path_spec[type]
63
+ end
64
+ end
65
+ end
66
+ end
data/lib/octopi/tag.rb ADDED
@@ -0,0 +1,16 @@
1
+ module Octopi
2
+ class Tag < Base
3
+ include Resource
4
+ set_resource_name "tag"
5
+
6
+ resource_path "/repos/show/:id"
7
+
8
+ def self.find(user, repo)
9
+ user = user.login if user.is_a? User
10
+ repo = repo.name if repo.is_a? Repository
11
+ find_plural([user,repo,'tags'], :resource){
12
+ |i| {:name => i.first, :hash => i.last }
13
+ }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,38 @@
1
+ module Octopi
2
+ class User < Base
3
+ include Resource
4
+
5
+ find_path "/user/search/:query"
6
+ resource_path "/user/show/:id"
7
+
8
+ def repositories
9
+ Repository.find_by_user(login)
10
+ end
11
+
12
+ def repository(name)
13
+ Repository.find(login, name)
14
+ end
15
+
16
+ # takes one param, deep that indicates if returns
17
+ # only the user login or an user object
18
+ %w[followers following].each do |method|
19
+ define_method(method) do
20
+ user_property(method, false)
21
+ end
22
+ define_method("#{method}!") do
23
+ user_property(method, true)
24
+ end
25
+ end
26
+
27
+ def user_property(property, deep)
28
+ users = []
29
+ property(property, login).each_pair do |k,v|
30
+ return v unless deep
31
+
32
+ v.each { |u| users << User.find(u) }
33
+ end
34
+
35
+ users
36
+ end
37
+ end
38
+ end
data/lib/octopi.rb CHANGED
@@ -12,6 +12,11 @@ module Octopi
12
12
 
13
13
  class Api
14
14
  include HTTParty
15
+ CONTENT_TYPE = {
16
+ 'yaml' => 'application/x-yaml',
17
+ 'json' => 'application/json',
18
+ 'xml' => 'application/sml'
19
+ }
15
20
  base_uri "http://github.com/api/v2"
16
21
 
17
22
  attr_accessor :format
@@ -46,207 +51,42 @@ module Octopi
46
51
  def find_all(path, result_key, query)
47
52
  get(path, { :query => query, :id => query })[result_key]
48
53
  end
49
-
54
+ def get_raw(path, params)
55
+ get(path, params, 'plain')
56
+ end
57
+
50
58
  private
51
59
  def get(path, params = {}, format = "yaml")
52
60
  params.each_pair do |k,v|
53
61
  path = path.gsub(":#{k.to_s}", v)
54
62
  end
55
- # puts "GET: /#{format}#{path}"
56
- self.class.get("/#{format}#{path}")
57
- end
58
- end
59
-
60
- class Base
61
- def initialize(api, hash)
62
- @api = api
63
- @keys = []
64
-
65
- raise "Missing data for #{@resource}" unless hash
66
-
67
- hash.each_pair do |k,v|
68
- @keys << k
69
- instance_variable_set("@#{k}", v)
70
-
71
- self.class.send :define_method, "#{k}=" do |v|
72
- instance_variable_set("@#{k}", v)
73
- end
74
-
75
- self.class.send :define_method, k do
76
- instance_variable_get("@#{k}")
77
- end
78
- end
79
- end
80
-
81
- def property(p, v)
82
- path = "#{self.class.path_for(:resource)}/#{p}"
83
- @api.find(path, self.class.resource_name(:singular), v)
84
- end
85
-
86
- def save
87
- hash = {}
88
- @keys.each { |k| hash[k] = send(k) }
89
- @api.save(self.path_for(:resource), hash)
90
- end
91
- end
92
-
93
- module Resource
94
- def self.included(base)
95
- base.extend ClassMethods
96
- base.set_resource_name(base.name)
97
- (@@resources||={})[base.resource_name(:singular)] = base
98
- (@@resources||={})[base.resource_name(:plural)] = base
99
- end
100
-
101
- def self.for(name)
102
- @@resources[name]
103
- end
104
-
105
- module ClassMethods
106
- def set_resource_name(singular, plural = "#{singular}s")
107
- @resource_name = {:singular => declassify(singular), :plural => declassify(plural)}
108
- end
109
-
110
- def resource_name(key)
111
- @resource_name[key]
112
- end
113
-
114
- def declassify(s)
115
- (s.split('::').last || '').downcase if s
116
- end
117
-
118
- def find_path(path)
119
- (@path_spec||={})[:find] = path
120
- end
121
-
122
- def resource_path(path)
123
- (@path_spec||={})[:resource] = path
124
- end
125
-
126
- def find(s)
127
- result = ANONYMOUS_API.find(path_for(:resource), @resource_name[:singular], s)
128
- key = result.keys.first
129
- Resource.for(key).new(ANONYMOUS_API, result[key])
130
- end
131
-
132
- def find_all(s)
133
- find_plural(s, :find)
134
- end
135
-
136
- def find_plural(s,path)
137
- all = []
138
- result = ANONYMOUS_API.find_all(path_for(path), @resource_name[:plural], s)
139
- result.each do |item|
140
- all << new(ANONYMOUS_API, item)
141
- end
142
- all
143
- end
144
-
145
- def path_for(type)
146
- @path_spec[type]
147
- end
148
- end
149
- end
150
-
151
- class User < Base
152
- include Resource
153
-
154
- find_path "/user/search/:query"
155
- resource_path "/user/show/:id"
156
-
157
- def repositories
158
- Repository.find_by_user(login)
159
- end
160
-
161
- def repository(name)
162
- Repository.find(login, name)
163
- end
164
-
165
- # takes one param, deep that indicates if returns
166
- # only the user login or an user object
167
- %w[followers following].each do |method|
168
- define_method(method) do
169
- user_property(method, false)
170
- end
171
- define_method("#{method}!") do
172
- user_property(method, true)
173
- end
174
- end
175
-
176
- def user_property(property, deep)
177
- users = []
178
- property(property, login).each_pair do |k,v|
179
- return v unless deep
180
-
181
- v.each { |u| users << User.find(u) }
182
- end
183
-
184
- users
63
+ resp = self.class.get("/#{format}#{path}")
64
+ # FIXME: This fails for showing raw Git data because that call returns
65
+ # text/html as the content type. This issue has been reported.
66
+ ctype = resp.headers['content-type'].first
67
+ raise FormatError, [ctype, format] unless
68
+ ctype.match(/^#{CONTENT_TYPE[format]};/)
69
+ raise APIError,
70
+ "GitHub returned status #{resp.code}" unless resp.code.to_i == 200
71
+ if format == 'yaml' && resp['error']
72
+ raise APIError, resp['error'].first['error']
73
+ end
74
+ resp
185
75
  end
186
76
  end
187
77
 
188
- class Repository < Base
189
- include Resource
190
- set_resource_name "repository", "repositories"
191
-
192
- find_path "/repos/search/:query"
193
- resource_path "/repos/show/:id"
194
-
195
- def self.find_by_user(user)
196
- find_plural(user, :resource)
197
- end
198
-
199
- def self.find(user, name)
200
- super "#{user}/#{name}"
201
- end
202
-
203
- def self.find_all(*args)
204
- super args.join("+")
205
- end
206
-
207
- def commits(branch = "master")
208
- Commit.find_all(owner, name, branch, self)
209
- end
210
- end
78
+ %w{base resource user tag repository file_object blob commit}.
79
+ each{|f| require "#{File.dirname(__FILE__)}/octopi/#{f}"}
80
+
81
+ class FormatError < StandardError
82
+ def initialize(f)
83
+ $stderr.puts "Got unexpected format (got #{f.first} for #{f.last})"
84
+ end
85
+ end
211
86
 
212
- class Commit < Base
213
- include Resource
214
- find_path "/commits/list/:query"
215
- resource_path "/commits/show/:id"
216
-
217
- attr_accessor :repository
218
-
219
- def self.find_all(user, name, branch = "master", repo = nil)
220
- commits = super("#{user}/#{name}/#{branch}")
221
- commits.each { |c| c.repository = repo } if repo
222
- commits
223
- end
224
-
225
- def self.find(*args)
226
- if args.last.is_a?(Commit)
227
- commit = args.pop
228
- super "#{commit.repo_identifier}"
229
- else
230
- user, name, sha = *args
231
- super "#{user}/#{name}/#{sha}"
232
- end
233
- end
234
-
235
- def details
236
- self.class.find(self)
237
- end
238
-
239
- def repo_identifier
240
- url_parts = url.split('/')
241
- if @repository
242
- parts = [@repository.owner, @repository.name, url_parts[6]]
243
- else
244
- parts = [url_parts[3], url_parts[4], url_parts[6]]
245
- end
246
-
247
- puts parts.join('/')
248
- parts.join('/')
249
- end
250
- end
251
- class APIError < StandardError; end
87
+ class APIError < StandardError
88
+ def initialize(m)
89
+ $stderr.puts m
90
+ end
91
+ end
252
92
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fcoury-octopi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felipe Coury
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-19 00:00:00 -07:00
12
+ date: 2009-04-20 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -25,6 +25,15 @@ extra_rdoc_files:
25
25
  files:
26
26
  - README.rdoc
27
27
  - VERSION.yml
28
+ - lib/octopi
29
+ - lib/octopi/base.rb
30
+ - lib/octopi/blob.rb
31
+ - lib/octopi/commit.rb
32
+ - lib/octopi/file_object.rb
33
+ - lib/octopi/repository.rb
34
+ - lib/octopi/resource.rb
35
+ - lib/octopi/tag.rb
36
+ - lib/octopi/user.rb
28
37
  - lib/octopi.rb
29
38
  - test/octopi_test.rb
30
39
  - test/test_helper.rb