octopi 0.1.0 → 0.2.1

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.
Files changed (53) hide show
  1. data/.gitignore +2 -1
  2. data/.yardoc +0 -0
  3. data/README.rdoc +16 -41
  4. data/Rakefile +9 -0
  5. data/VERSION.yml +2 -2
  6. data/examples/overall.rb +1 -1
  7. data/lib/ext/hash_ext.rb +5 -0
  8. data/lib/ext/string_ext.rb +5 -0
  9. data/lib/octopi.rb +101 -202
  10. data/lib/octopi/api.rb +209 -0
  11. data/lib/octopi/base.rb +42 -38
  12. data/lib/octopi/blob.rb +12 -8
  13. data/lib/octopi/branch.rb +20 -7
  14. data/lib/octopi/branch_set.rb +11 -0
  15. data/lib/octopi/comment.rb +20 -0
  16. data/lib/octopi/commit.rb +39 -35
  17. data/lib/octopi/error.rb +17 -5
  18. data/lib/octopi/file_object.rb +6 -5
  19. data/lib/octopi/gist.rb +28 -0
  20. data/lib/octopi/issue.rb +49 -40
  21. data/lib/octopi/issue_comment.rb +7 -0
  22. data/lib/octopi/issue_set.rb +21 -0
  23. data/lib/octopi/key.rb +14 -7
  24. data/lib/octopi/key_set.rb +14 -0
  25. data/lib/octopi/plan.rb +5 -0
  26. data/lib/octopi/repository.rb +66 -45
  27. data/lib/octopi/repository_set.rb +9 -0
  28. data/lib/octopi/resource.rb +11 -16
  29. data/lib/octopi/self.rb +33 -0
  30. data/lib/octopi/tag.rb +12 -6
  31. data/lib/octopi/user.rb +62 -38
  32. data/octopi.gemspec +43 -12
  33. data/test/api_test.rb +58 -0
  34. data/test/authenticated_test.rb +39 -0
  35. data/test/blob_test.rb +23 -0
  36. data/test/branch_test.rb +20 -0
  37. data/test/commit_test.rb +82 -0
  38. data/test/file_object_test.rb +39 -0
  39. data/test/gist_test.rb +16 -0
  40. data/test/issue_comment.rb +19 -0
  41. data/test/issue_set_test.rb +33 -0
  42. data/test/issue_test.rb +120 -0
  43. data/test/key_set_test.rb +29 -0
  44. data/test/key_test.rb +35 -0
  45. data/test/repository_set_test.rb +23 -0
  46. data/test/repository_test.rb +141 -0
  47. data/test/stubs/commits/fcoury/octopi/octopi.rb +818 -0
  48. data/test/tag_test.rb +20 -0
  49. data/test/test_helper.rb +236 -0
  50. data/test/user_test.rb +92 -0
  51. metadata +54 -12
  52. data/examples/github.yml.example +0 -14
  53. data/test/octopi_test.rb +0 -46
@@ -0,0 +1,9 @@
1
+ require File.join(File.dirname(__FILE__), "repository")
2
+ class Octopi::RepositorySet < Array
3
+ include Octopi
4
+ attr_accessor :user
5
+
6
+ def find(name)
7
+ Octopi::Repository.find(:user => self.user, :repository => name)
8
+ end
9
+ end
@@ -37,30 +37,25 @@ module Octopi
37
37
  end
38
38
 
39
39
  def find(*args)
40
- api = args.last.is_a?(Api) ? args.pop : ANONYMOUS_API
41
40
  args = args.join('/') if args.is_a? Array
42
- result = api.find(path_for(:resource), @resource_name[:singular], args)
41
+ result = Api.api.find(path_for(:resource), @resource_name[:singular], args, self, @cache)
43
42
  key = result.keys.first
44
43
 
45
44
  if result[key].is_a? Array
46
- result[key].map { |r| new(api, r) }
47
- else
48
- Resource.for(key).new(api, result[key])
49
- end
45
+ result[key].map { |r| new(r) }
46
+ else
47
+ Resource.for(key).new(result[key])
48
+ end
50
49
  end
51
-
50
+
52
51
  def find_all(*s)
53
- api = s.last.is_a?(Api) ? s.pop : ANONYMOUS_API
54
- find_plural(s, :find, api)
52
+ find_plural(s, :find)
55
53
  end
56
-
57
- def find_plural(s, path, api = ANONYMOUS_API)
54
+
55
+ def find_plural(s, path)
58
56
  s = s.join('/') if s.is_a? Array
59
- api.find_all(path_for(path), @resource_name[:plural], s).
60
- map do |item|
61
- payload = block_given? ? yield(item) : item
62
- new(api, payload)
63
- end
57
+ resources = Api.api.find_all(path_for(path), @resource_name[:plural], s, self)
58
+ resources.map { |item| self.new(item) }
64
59
  end
65
60
 
66
61
  def declassify(s)
@@ -0,0 +1,33 @@
1
+ module Octopi
2
+ module Self
3
+ # Returns a list of Key objects containing all SSH Public Keys this user
4
+ # currently has. Requires authentication.
5
+ def keys
6
+ raise AuthenticationRequired, "To view keys, you must be authenticated" if Api.api.read_only?
7
+ result = Api.api.get("/user/keys", { :cache => false })
8
+ return unless result and result["public_keys"]
9
+ KeySet.new(result["public_keys"].inject([]) { |result, element| result << Key.new(element) })
10
+ end
11
+
12
+ # Returns a list of Email objects containing the email addresses associated with this user.
13
+ # Requires authentication.
14
+ def emails
15
+ raise AuthenticationRequired, "To view emails, you must be authenticated" if Api.api.read_only?
16
+ get("/user/emails")['emails']
17
+ end
18
+
19
+ # Start following a user.
20
+ # Can only be called if you are authenticated.
21
+ def follow!(login)
22
+ raise AuthenticationRequired, "To begin following someone, you must be authenticated" if Api.api.read_only?
23
+ Api.api.post("/user/follow/#{login}")
24
+ end
25
+
26
+ # Stop following a user.
27
+ # Can only be called if you are authenticated.
28
+ def unfollow!(login)
29
+ raise AuthenticationRequired, "To stop following someone, you must be authenticated" if Api.api.read_only?
30
+ Api.api.post("/user/unfollow/#{login}")
31
+ end
32
+ end
33
+ end
data/lib/octopi/tag.rb CHANGED
@@ -1,17 +1,23 @@
1
1
  module Octopi
2
2
  class Tag < Base
3
3
  include Resource
4
+
5
+ attr_accessor :name, :sha
4
6
  set_resource_name "tag"
5
7
 
6
8
  resource_path "/repos/show/:id"
7
9
 
8
- def self.find(user, repo)
9
- user = user.login if user.is_a? User
10
- repo = repo.name if repo.is_a? Repository
10
+ def initialize(*args)
11
+ args = args.flatten!
12
+ self.name = args.first
13
+ self.sha = args.last
14
+ end
15
+
16
+ def self.all(options={})
17
+ ensure_hash(options)
18
+ user, repo = gather_details(options)
11
19
  self.validate_args(user => :user, repo => :repo)
12
- find_plural([user,repo,'tags'], :resource){
13
- |i| {:name => i.first, :hash => i.last }
14
- }
20
+ find_plural([user, repo, 'tags'], :resource) { |i| Tag.new(i) }
15
21
  end
16
22
  end
17
23
  end
data/lib/octopi/user.rb CHANGED
@@ -1,10 +1,17 @@
1
1
  module Octopi
2
2
  class User < Base
3
3
  include Resource
4
+ attr_accessor :company, :name, :following_count, :blog, :public_repo_count, :public_gist_count, :id, :login, :followers_count, :created_at, :email, :location, :disk_usage, :private_repo_count, :private_gist_count, :collaborators, :plan, :owned_private_repo_count, :total_private_repo_count,
5
+ # These come from search results, which doesn't contain the above information.
6
+ :actions, :score, :language, :followers, :following, :fullname, :type, :username, :repos, :pushed, :created
7
+
8
+ def plan=(attributes={})
9
+ @plan = Plan.new(attributes)
10
+ end
4
11
 
5
12
  find_path "/user/search/:query"
6
13
  resource_path "/user/show/:id"
7
-
14
+
8
15
  # Finds a single user identified by the given username
9
16
  #
10
17
  # Example:
@@ -26,6 +33,10 @@ module Octopi
26
33
  self.validate_args(username => :user)
27
34
  super username
28
35
  end
36
+
37
+ class << self
38
+ alias_method :search, :find_all
39
+ end
29
40
 
30
41
  # Returns a collection of Repository objects, containing
31
42
  # all repositories of the user.
@@ -34,58 +45,70 @@ module Octopi
34
45
  # additional information will be provided for the
35
46
  # Repositories.
36
47
  def repositories
37
- api = self.api || ANONYMOUS_API
38
- Repository.find_by_user(login,api)
48
+ rs = RepositorySet.new(Repository.find(:user => self.login))
49
+ rs.user = self
50
+ rs
39
51
  end
40
52
 
41
- # Searches for user Repository identified by
42
- # name
43
- def repository(name)
44
- self.class.validate_args(name => :repo)
45
- Repository.find(login, name)
53
+ # Searches for user Repository identified by name
54
+ def repository(options={})
55
+ options = { :name => options } if options.is_a?(String)
56
+ self.class.ensure_hash(options)
57
+ Repository.find({ :user => login }.merge!(options))
46
58
  end
47
59
 
48
- def create_repository(name, opts = {})
60
+ def create_repository(name, options = {})
49
61
  self.class.validate_args(name => :repo)
50
- Repository.create(self, name, opts)
62
+ Repository.create(self, name, options)
63
+ end
64
+
65
+ def watching
66
+ repositories = []
67
+ Api.api.get("/repos/watched/#{login}")["repositories"].each do |repo|
68
+ repositories << Repository.new(repo)
69
+ end
70
+ repositories
51
71
  end
52
72
 
53
- # Adds an SSH Public Key to the user. Requires
54
- # authentication.
55
- def add_key(title, key)
56
- raise APIError,
57
- "To add a key, you must be authenticated" if @api.read_only?
58
73
 
59
- result = @api.post("/user/key/add", :title => title, :key => key)
60
- return if !result["public_keys"]
61
- key_params = result["public_keys"].select { |k| k["title"] == title }
62
- return if !key_params or key_params.empty?
63
- Key.new(@api, key_params.first, self)
74
+ # Gets a list of followers.
75
+ # Returns an array of logins.
76
+ def followers
77
+ user_property("followers")
64
78
  end
65
79
 
66
- # Returns a list of Key objects containing all SSH Public Keys this user
67
- # currently has. Requires authentication.
68
- def keys
69
- raise APIError,
70
- "To add a key, you must be authenticated" if @api.read_only?
80
+ # Gets a list of followers.
81
+ # Returns an array of user objects.
82
+ # If user has a large number of followers you may be rate limited by the API.
83
+ def followers!
84
+ user_property("followers", true)
85
+ end
71
86
 
72
- result = @api.get("/user/keys")
73
- return unless result and result["public_keys"]
74
- result["public_keys"].inject([]) { |result, element| result << Key.new(@api, element) }
87
+ # Gets a list of people this user is following.
88
+ # Returns an array of logins.
89
+ def following
90
+ user_property("following")
75
91
  end
92
+
93
+ # Gets a list of people this user is following.
94
+ # Returns an array of user objectrs.
95
+ # If user has a large number of people whom they follow, you may be rate limited by the API.
96
+ def following!
97
+ user_property("following", true)
98
+ end
99
+
76
100
 
77
- # takes one param, deep that indicates if returns
78
- # only the user login or an user object
79
- %w[followers following].each do |method|
80
- define_method(method) do
81
- user_property(method, false)
82
- end
83
- define_method("#{method}!") do
84
- user_property(method, true)
85
- end
101
+ # If a user object is passed into a method, we can use this.
102
+ # It'll also work if we pass in just the login.
103
+ def to_s
104
+ login
86
105
  end
87
106
 
88
- def user_property(property, deep)
107
+ private
108
+
109
+ # Helper method for "deep" finds.
110
+ # Determines whether to return an array of logins (light) or user objects (heavy).
111
+ def user_property(property, deep=false)
89
112
  users = []
90
113
  property(property, login).each_pair do |k,v|
91
114
  return v unless deep
@@ -95,5 +118,6 @@ module Octopi
95
118
 
96
119
  users
97
120
  end
121
+
98
122
  end
99
123
  end
data/octopi.gemspec CHANGED
@@ -1,12 +1,15 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
1
4
  # -*- encoding: utf-8 -*-
2
5
 
3
6
  Gem::Specification.new do |s|
4
7
  s.name = %q{octopi}
5
- s.version = "0.1.0"
8
+ s.version = "0.2.1"
6
9
 
7
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
11
  s.authors = ["Felipe Coury"]
9
- s.date = %q{2009-07-21}
12
+ s.date = %q{2009-11-10}
10
13
  s.email = %q{felipe.coury@gmail.com}
11
14
  s.extra_rdoc_files = [
12
15
  "LICENSE",
@@ -14,42 +17,64 @@ Gem::Specification.new do |s|
14
17
  ]
15
18
  s.files = [
16
19
  ".gitignore",
20
+ ".yardoc",
17
21
  "LICENSE",
18
22
  "README.rdoc",
19
23
  "Rakefile",
20
24
  "VERSION.yml",
21
25
  "contrib/backup.rb",
22
- "examples/authenticated.rb",
23
- "examples/github.yml.example",
24
- "examples/issues.rb",
25
- "examples/overall.rb",
26
+ "lib/ext/hash_ext.rb",
27
+ "lib/ext/string_ext.rb",
26
28
  "lib/octopi.rb",
29
+ "lib/octopi/api.rb",
27
30
  "lib/octopi/base.rb",
28
31
  "lib/octopi/blob.rb",
29
32
  "lib/octopi/branch.rb",
33
+ "lib/octopi/branch_set.rb",
34
+ "lib/octopi/comment.rb",
30
35
  "lib/octopi/commit.rb",
31
36
  "lib/octopi/error.rb",
32
37
  "lib/octopi/file_object.rb",
38
+ "lib/octopi/gist.rb",
33
39
  "lib/octopi/issue.rb",
40
+ "lib/octopi/issue_comment.rb",
41
+ "lib/octopi/issue_set.rb",
34
42
  "lib/octopi/key.rb",
43
+ "lib/octopi/key_set.rb",
44
+ "lib/octopi/plan.rb",
35
45
  "lib/octopi/repository.rb",
46
+ "lib/octopi/repository_set.rb",
36
47
  "lib/octopi/resource.rb",
48
+ "lib/octopi/self.rb",
37
49
  "lib/octopi/tag.rb",
38
50
  "lib/octopi/user.rb",
39
- "octopi.gemspec",
40
- "test/octopi_test.rb",
41
- "test/test_helper.rb"
51
+ "octopi.gemspec"
42
52
  ]
43
- s.has_rdoc = true
44
53
  s.homepage = %q{http://github.com/fcoury/octopi}
45
54
  s.rdoc_options = ["--charset=UTF-8"]
46
55
  s.require_paths = ["lib"]
47
56
  s.rubyforge_project = %q{octopi}
48
- s.rubygems_version = %q{1.3.2}
57
+ s.rubygems_version = %q{1.3.5}
49
58
  s.summary = %q{A Ruby interface to GitHub API v2}
50
59
  s.test_files = [
51
- "test/octopi_test.rb",
60
+ "test/api_test.rb",
61
+ "test/authenticated_test.rb",
62
+ "test/blob_test.rb",
63
+ "test/branch_test.rb",
64
+ "test/commit_test.rb",
65
+ "test/file_object_test.rb",
66
+ "test/gist_test.rb",
67
+ "test/issue_comment.rb",
68
+ "test/issue_set_test.rb",
69
+ "test/issue_test.rb",
70
+ "test/key_set_test.rb",
71
+ "test/key_test.rb",
72
+ "test/repository_set_test.rb",
73
+ "test/repository_test.rb",
74
+ "test/stubs/commits/fcoury/octopi/octopi.rb",
75
+ "test/tag_test.rb",
52
76
  "test/test_helper.rb",
77
+ "test/user_test.rb",
53
78
  "examples/authenticated.rb",
54
79
  "examples/issues.rb",
55
80
  "examples/overall.rb"
@@ -60,8 +85,14 @@ Gem::Specification.new do |s|
60
85
  s.specification_version = 3
61
86
 
62
87
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
88
+ s.add_runtime_dependency(%q<nokogiri>, [">= 1.3.1"])
89
+ s.add_runtime_dependency(%q<httparty>, [">= 0.4.5"])
63
90
  else
91
+ s.add_dependency(%q<nokogiri>, [">= 1.3.1"])
92
+ s.add_dependency(%q<httparty>, [">= 0.4.5"])
64
93
  end
65
94
  else
95
+ s.add_dependency(%q<nokogiri>, [">= 1.3.1"])
96
+ s.add_dependency(%q<httparty>, [">= 0.4.5"])
66
97
  end
67
98
  end
data/test/api_test.rb ADDED
@@ -0,0 +1,58 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class AuthenticatedTest < Test::Unit::TestCase
4
+ include Octopi
5
+
6
+ def setup
7
+ fake_everything
8
+ @user = User.find("fcoury")
9
+ end
10
+
11
+ context "following" do
12
+
13
+ should "not be able to follow anyone if not authenticated" do
14
+ exception = assert_raise AuthenticationRequired do
15
+ Api.me.follow!("rails")
16
+ end
17
+ end
18
+
19
+ should "be able to follow a user" do
20
+ auth do
21
+ assert_not_nil Api.me.follow!("rails")
22
+ end
23
+ end
24
+ end
25
+
26
+ context "unfollowing" do
27
+
28
+ should "not be able to follow anyone if not authenticated" do
29
+ exception = assert_raise AuthenticationRequired do
30
+ Api.me.unfollow!("rails")
31
+ end
32
+ end
33
+
34
+ should "be able to follow a user" do
35
+ auth do
36
+ assert_not_nil Api.me.unfollow!("rails")
37
+ end
38
+ end
39
+ end
40
+
41
+ context "keys" do
42
+ should "not be able to see keys if not authenticated" do
43
+ exception = assert_raise AuthenticationRequired do
44
+ Api.me.keys
45
+ end
46
+
47
+ assert_equal "To view keys, you must be authenticated", exception.message
48
+ end
49
+
50
+ should "have some keys" do
51
+ auth do
52
+ keys = Api.me.keys
53
+ assert keys.is_a?(KeySet)
54
+ assert_equal 2, keys.size
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,39 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class AuthenticatedTest < Test::Unit::TestCase
4
+ include Octopi
5
+ def setup
6
+ fake_everything
7
+ end
8
+
9
+ context "Authenticating" do
10
+ should "be possible with username and password" do
11
+ authenticated_with(:login => "fcoury", :password => "yruocf") do
12
+ assert_equal "8f700e0d7747826f3e56ee13651414bd", Api.api.token
13
+ assert_not_nil User.find("fcoury")
14
+ end
15
+ end
16
+
17
+ should "be possible with username and token" do
18
+ auth do
19
+ assert_not_nil User.find("fcoury")
20
+ end
21
+ end
22
+
23
+ should "be possible using the .gitconfig" do
24
+ authenticated do
25
+ assert_not_nil User.find("fcoury")
26
+ end
27
+ end
28
+ #
29
+ # should "be denied access when specifying an invalid token and login combination" do
30
+ # FakeWeb.clean_registry
31
+ # FakeWeb.register_uri(:get, "http://github.com/api/v2/yaml/user/show/fcoury", :status => ["404", "Not Found"])
32
+ # assert_raise InvalidLogin do
33
+ # authenticated_with :login => "fcoury", :token => "ba7bf2d7f0ebc073d3874dda887b18ae" do
34
+ # # Just blank will do us fine.
35
+ # end
36
+ # end
37
+ # end
38
+ end
39
+ end