devver-octopi 0.2.8

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 (56) hide show
  1. data/.gitignore +4 -0
  2. data/.yardoc +0 -0
  3. data/CHANGELOG.md +9 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +144 -0
  6. data/Rakefile +100 -0
  7. data/VERSION.yml +5 -0
  8. data/contrib/backup.rb +100 -0
  9. data/examples/authenticated.rb +20 -0
  10. data/examples/issues.rb +18 -0
  11. data/examples/overall.rb +50 -0
  12. data/lib/ext/hash_ext.rb +5 -0
  13. data/lib/ext/string_ext.rb +5 -0
  14. data/lib/octopi.rb +136 -0
  15. data/lib/octopi/api.rb +213 -0
  16. data/lib/octopi/base.rb +115 -0
  17. data/lib/octopi/blob.rb +25 -0
  18. data/lib/octopi/branch.rb +31 -0
  19. data/lib/octopi/branch_set.rb +11 -0
  20. data/lib/octopi/comment.rb +20 -0
  21. data/lib/octopi/commit.rb +69 -0
  22. data/lib/octopi/error.rb +35 -0
  23. data/lib/octopi/file_object.rb +16 -0
  24. data/lib/octopi/gist.rb +28 -0
  25. data/lib/octopi/issue.rb +111 -0
  26. data/lib/octopi/issue_comment.rb +7 -0
  27. data/lib/octopi/issue_set.rb +21 -0
  28. data/lib/octopi/key.rb +25 -0
  29. data/lib/octopi/key_set.rb +14 -0
  30. data/lib/octopi/plan.rb +5 -0
  31. data/lib/octopi/repository.rb +132 -0
  32. data/lib/octopi/repository_set.rb +9 -0
  33. data/lib/octopi/resource.rb +70 -0
  34. data/lib/octopi/self.rb +33 -0
  35. data/lib/octopi/tag.rb +23 -0
  36. data/lib/octopi/user.rb +123 -0
  37. data/octopi.gemspec +99 -0
  38. data/test/api_test.rb +58 -0
  39. data/test/authenticated_test.rb +39 -0
  40. data/test/blob_test.rb +23 -0
  41. data/test/branch_test.rb +20 -0
  42. data/test/commit_test.rb +82 -0
  43. data/test/file_object_test.rb +39 -0
  44. data/test/gist_test.rb +16 -0
  45. data/test/issue_comment.rb +19 -0
  46. data/test/issue_set_test.rb +33 -0
  47. data/test/issue_test.rb +120 -0
  48. data/test/key_set_test.rb +29 -0
  49. data/test/key_test.rb +35 -0
  50. data/test/repository_set_test.rb +23 -0
  51. data/test/repository_test.rb +151 -0
  52. data/test/stubs/commits/fcoury/octopi/octopi.rb +818 -0
  53. data/test/tag_test.rb +20 -0
  54. data/test/test_helper.rb +246 -0
  55. data/test/user_test.rb +92 -0
  56. metadata +153 -0
@@ -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
@@ -0,0 +1,70 @@
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 create_path(path)
24
+ (@path_spec||={})[:create] = path
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 delete_path(path)
36
+ (@path_spec||={})[:delete] = path
37
+ end
38
+
39
+ def find(*args)
40
+ args = args.join('/') if args.is_a? Array
41
+ result = Api.api.find(path_for(:resource), @resource_name[:singular], args, self, @cache)
42
+ key = result.keys.first
43
+
44
+ if result[key].is_a? Array
45
+ result[key].map { |r| new(r) }
46
+ else
47
+ Resource.for(key).new(result[key])
48
+ end
49
+ end
50
+
51
+ def find_all(*s)
52
+ find_plural(s, :find)
53
+ end
54
+
55
+ def find_plural(s, path)
56
+ s = s.join('/') if s.is_a? Array
57
+ resources = Api.api.find_all(path_for(path), @resource_name[:plural], s, self)
58
+ resources.map { |item| self.new(item) }
59
+ end
60
+
61
+ def declassify(s)
62
+ (s.split('::').last || '').downcase if s
63
+ end
64
+
65
+ def path_for(type)
66
+ @path_spec[type]
67
+ end
68
+ end
69
+ end
70
+ end
@@ -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 ADDED
@@ -0,0 +1,23 @@
1
+ module Octopi
2
+ class Tag < Base
3
+ include Resource
4
+
5
+ attr_accessor :name, :sha
6
+ set_resource_name "tag"
7
+
8
+ resource_path "/repos/show/:id"
9
+
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)
19
+ self.validate_args(user => :user, repo => :repo)
20
+ find_plural([user, repo, 'tags'], :resource) { |i| Tag.new(i) }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,123 @@
1
+ module Octopi
2
+ class User < Base
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
11
+
12
+ find_path "/user/search/:query"
13
+ resource_path "/user/show/:id"
14
+
15
+ # Finds a single user identified by the given username
16
+ #
17
+ # Example:
18
+ #
19
+ # user = User.find("fcoury")
20
+ # puts user.login # should return 'fcoury'
21
+ def self.find(username)
22
+ self.validate_args(username => :user)
23
+ super username
24
+ end
25
+
26
+ # Finds all users whose username matches a given string
27
+ #
28
+ # Example:
29
+ #
30
+ # User.find_all("oe") # Matches joe, moe and monroe
31
+ #
32
+ def self.find_all(username)
33
+ self.validate_args(username => :user)
34
+ super username
35
+ end
36
+
37
+ class << self
38
+ alias_method :search, :find_all
39
+ end
40
+
41
+ # Returns a collection of Repository objects, containing
42
+ # all repositories of the user.
43
+ #
44
+ # If user is the current authenticated user, some
45
+ # additional information will be provided for the
46
+ # Repositories.
47
+ def repositories
48
+ rs = RepositorySet.new(Repository.find(:user => self.login))
49
+ rs.user = self
50
+ rs
51
+ end
52
+
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))
58
+ end
59
+
60
+ def create_repository(name, options = {})
61
+ self.class.validate_args(name => :repo)
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
71
+ end
72
+
73
+
74
+ # Gets a list of followers.
75
+ # Returns an array of logins.
76
+ def followers
77
+ user_property("followers")
78
+ end
79
+
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
86
+
87
+ # Gets a list of people this user is following.
88
+ # Returns an array of logins.
89
+ def following
90
+ user_property("following")
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
+
100
+
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
105
+ end
106
+
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)
112
+ users = []
113
+ property(property, login).each_pair do |k,v|
114
+ return v unless deep
115
+
116
+ v.each { |u| users << User.find(u) }
117
+ end
118
+
119
+ users
120
+ end
121
+
122
+ end
123
+ end
data/octopi.gemspec ADDED
@@ -0,0 +1,99 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
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{octopi}
8
+ s.version = "0.2.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Felipe Coury"]
12
+ s.date = %q{2009-12-26}
13
+ s.email = %q{felipe.coury@gmail.com}
14
+ s.extra_rdoc_files = [
15
+ "LICENSE",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ ".yardoc",
21
+ "CHANGELOG.md",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION.yml",
26
+ "contrib/backup.rb",
27
+ "lib/ext/hash_ext.rb",
28
+ "lib/ext/string_ext.rb",
29
+ "lib/octopi.rb",
30
+ "lib/octopi/api.rb",
31
+ "lib/octopi/base.rb",
32
+ "lib/octopi/blob.rb",
33
+ "lib/octopi/branch.rb",
34
+ "lib/octopi/branch_set.rb",
35
+ "lib/octopi/comment.rb",
36
+ "lib/octopi/commit.rb",
37
+ "lib/octopi/error.rb",
38
+ "lib/octopi/file_object.rb",
39
+ "lib/octopi/gist.rb",
40
+ "lib/octopi/issue.rb",
41
+ "lib/octopi/issue_comment.rb",
42
+ "lib/octopi/issue_set.rb",
43
+ "lib/octopi/key.rb",
44
+ "lib/octopi/key_set.rb",
45
+ "lib/octopi/plan.rb",
46
+ "lib/octopi/repository.rb",
47
+ "lib/octopi/repository_set.rb",
48
+ "lib/octopi/resource.rb",
49
+ "lib/octopi/self.rb",
50
+ "lib/octopi/tag.rb",
51
+ "lib/octopi/user.rb",
52
+ "octopi.gemspec"
53
+ ]
54
+ s.homepage = %q{http://github.com/fcoury/octopi}
55
+ s.rdoc_options = ["--charset=UTF-8"]
56
+ s.require_paths = ["lib"]
57
+ s.rubyforge_project = %q{octopi}
58
+ s.rubygems_version = %q{1.3.5}
59
+ s.summary = %q{A Ruby interface to GitHub API v2}
60
+ s.test_files = [
61
+ "test/api_test.rb",
62
+ "test/authenticated_test.rb",
63
+ "test/blob_test.rb",
64
+ "test/branch_test.rb",
65
+ "test/commit_test.rb",
66
+ "test/file_object_test.rb",
67
+ "test/gist_test.rb",
68
+ "test/issue_comment.rb",
69
+ "test/issue_set_test.rb",
70
+ "test/issue_test.rb",
71
+ "test/key_set_test.rb",
72
+ "test/key_test.rb",
73
+ "test/repository_set_test.rb",
74
+ "test/repository_test.rb",
75
+ "test/stubs/commits/fcoury/octopi/octopi.rb",
76
+ "test/tag_test.rb",
77
+ "test/test_helper.rb",
78
+ "test/user_test.rb",
79
+ "examples/authenticated.rb",
80
+ "examples/issues.rb",
81
+ "examples/overall.rb"
82
+ ]
83
+
84
+ if s.respond_to? :specification_version then
85
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
86
+ s.specification_version = 3
87
+
88
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
89
+ s.add_runtime_dependency(%q<nokogiri>, [">= 1.3.1"])
90
+ s.add_runtime_dependency(%q<httparty>, [">= 0.4.5"])
91
+ else
92
+ s.add_dependency(%q<nokogiri>, [">= 1.3.1"])
93
+ s.add_dependency(%q<httparty>, [">= 0.4.5"])
94
+ end
95
+ else
96
+ s.add_dependency(%q<nokogiri>, [">= 1.3.1"])
97
+ s.add_dependency(%q<httparty>, [">= 0.4.5"])
98
+ end
99
+ 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