github_metadata 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ pkg/*
2
+ tmp/*
3
+ coverage
4
+ rdoc
5
+ *.gem
6
+ .bundle
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in github_metadata.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,31 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ github_metadata (0.1.0)
5
+ nokogiri
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.1.2)
11
+ nokogiri (1.4.4)
12
+ rspec (2.4.0)
13
+ rspec-core (~> 2.4.0)
14
+ rspec-expectations (~> 2.4.0)
15
+ rspec-mocks (~> 2.4.0)
16
+ rspec-core (2.4.0)
17
+ rspec-expectations (2.4.0)
18
+ diff-lcs (~> 1.1.2)
19
+ rspec-mocks (2.4.0)
20
+ simplecov (0.3.7)
21
+ simplecov-html (>= 0.3.7)
22
+ simplecov-html (0.3.9)
23
+
24
+ PLATFORMS
25
+ ruby
26
+
27
+ DEPENDENCIES
28
+ github_metadata!
29
+ nokogiri
30
+ rspec (>= 2.0.0)
31
+ simplecov
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Christoph Olszowka
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.
data/README.rdoc ADDED
@@ -0,0 +1,52 @@
1
+ = Github Metadata
2
+
3
+ The Github repository API does not include all the information available on the
4
+ web view of a repo. It also has some trouble reporting correctly the availability of
5
+ a wiki and issues.
6
+
7
+ The github_metadata gem is here to solve this. Currently it gives you, for any github repo:
8
+
9
+ * The availability and (if present) the count of wiki pages
10
+ * The availability and (if present) the count of issues
11
+ * The count of pull requests
12
+ * The list of contributors, with username and real name if available, and thereby also
13
+ the count of contributors
14
+
15
+ By the way: It goes very easy on the github servers in doing so, currently only performing 1 request
16
+ to fetch all of the information per instance.
17
+
18
+ == Usage
19
+
20
+ $ gem install github_metadata
21
+ $ irb
22
+ > require 'github_metadata'
23
+ > m = GithubMetadata.new('aslakhellesoy', 'cucumber')
24
+ > m.has_wiki?
25
+ => true
26
+ > m.wiki_pages
27
+ => 71
28
+ > m.has_issues?
29
+ => false
30
+ > m.contributor_usernames
31
+ => ['aslakhellesoy', ...]
32
+
33
+ Check out the full documentation to see all available methods.
34
+
35
+ == TODO
36
+
37
+ * Better (any?) error handling
38
+ * Merge with my very own first_github_commit gem, which retrieves the very first commit to a repo
39
+
40
+ == Note on Patches/Pull Requests
41
+
42
+ * Fork the project.
43
+ * Make your feature addition or bug fix.
44
+ * Add tests for it. This is important so I don't break it in a
45
+ future version unintentionally.
46
+ * Commit, do not mess with rakefile, version, or history.
47
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
48
+ * Send me a pull request. Bonus points for topic branches.
49
+
50
+ == Copyright
51
+
52
+ Copyright (c) 2011 Christoph Olszowka. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "github_metadata/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "github_metadata"
7
+ s.version = GithubMetadata::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Christoph Olszowka"]
10
+ s.email = ["christoph at olszowka de"]
11
+ s.homepage = ""
12
+ s.summary = %q{Extracts additional information from Github repos that isn't available via API}
13
+ s.description = %q{Extracts additional information like amount of committers, issues and wiki pages from Github repos}
14
+
15
+ s.rubyforge_project = "github_metadata"
16
+
17
+ s.add_dependency 'nokogiri'
18
+ s.add_development_dependency 'rspec', '>= 2.0.0'
19
+ s.add_development_dependency 'simplecov'
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
+ s.require_paths = ["lib"]
25
+ end
@@ -0,0 +1,3 @@
1
+ class GithubMetadata
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,98 @@
1
+ require 'rubygems'
2
+ require 'open-uri'
3
+ require 'nokogiri'
4
+
5
+ # A simple scraper that fetches data from github repos that is not
6
+ # available via the API. See README for an introduction and overview.
7
+ class GithubMetadata
8
+ attr_reader :user, :repo
9
+
10
+ # Object representation of a github contributor
11
+ class Contributor
12
+ attr_reader :username, :realname
13
+ def initialize(username, realname=nil)
14
+ @username, @realname = username, realname
15
+ end
16
+ end
17
+
18
+ def initialize(user, repo)
19
+ @user, @repo = user, repo
20
+ end
21
+
22
+ # Returns an array of GithubMetadata::Contributor instances, one for each
23
+ # contributor listed on the contributors page of github
24
+ def contributors
25
+ load_contributors unless @contributors
26
+ @contributors
27
+ end
28
+
29
+ # Shorthand form for getting an array of all contributor github usernames
30
+ def contributor_usernames
31
+ @contributor_usernames ||= contributors.map(&:username)
32
+ end
33
+
34
+ # Shorthand form for getting an array of all contributor github realnames,
35
+ # with users that don't have a realname specified filtered out
36
+ def contributor_realnames
37
+ @contributor_realnames ||= contributors.map(&:realname).compact
38
+ end
39
+
40
+ # Will return all contributor real names, falling back to the username when
41
+ # real name is not specified
42
+ def contributor_names
43
+ @contributor_names ||= contributors.map {|c| c.realname || c.username }
44
+ end
45
+
46
+ # Returns true when the repo has a wiki
47
+ def has_wiki?
48
+ !!wiki_pages
49
+ end
50
+
51
+ # Returns the amount of wiki pages or nil when no wiki is present
52
+ def wiki_pages
53
+ wiki_link = document.at_css('a[highlight="repo_wiki"]')
54
+ return nil unless wiki_link
55
+ wiki_link.text[/\d+/].to_i
56
+ end
57
+
58
+ # Returns true if the repo has issues enabled
59
+ def has_issues?
60
+ !!issues
61
+ end
62
+
63
+ # Returns issue count or nil if issues are disabled
64
+ def issues
65
+ issue_link = document.at_css('a[highlight="issues"]')
66
+ return nil unless issue_link
67
+ issue_link.text[/\d+/].to_i
68
+ end
69
+
70
+ # Returns amount of pull requests
71
+ def pull_requests
72
+ pull_request_link = document.at_css('a[highlight="repo_pulls"]')
73
+ return nil unless pull_request_link
74
+ pull_request_link.text[/\d+/].to_i
75
+ end
76
+
77
+ private
78
+
79
+ def document
80
+ @document ||= Nokogiri::HTML(open(contributors_url))
81
+ end
82
+
83
+ def contributors_url
84
+ "https://github.com/#{user}/#{repo}/contributors"
85
+ end
86
+
87
+ def load_contributors
88
+ @contributors = document.css('#repos #watchers.members li').map do |contributor|
89
+ line = contributor.text.gsub("\n", '').squeeze(' ').strip.chomp
90
+ username = line.match(/^([^\ ]+)/)[1]
91
+
92
+ name_match = line.match(/\(([^\)]+)\)/)
93
+ real_name = name_match ? name_match[1] : nil
94
+
95
+ GithubMetadata::Contributor.new(username, real_name)
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,169 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ describe GithubMetadata do
4
+ context "initialized with aslakhellesoy/cucumber" do
5
+ before(:all) do
6
+ @metadata = GithubMetadata.new('aslakhellesoy', 'cucumber')
7
+ @raw = open("https://github.com/#{@metadata.user}/#{@metadata.repo}/contributors").read
8
+ end
9
+ subject { @metadata }
10
+
11
+ describe '#user' do
12
+ specify do
13
+ subject.user.should == 'aslakhellesoy'
14
+ end
15
+ end
16
+
17
+ describe '#repo' do
18
+ specify do
19
+ subject.repo.should == 'cucumber'
20
+ end
21
+ end
22
+
23
+ specify do
24
+ subject.should have_wiki
25
+ end
26
+
27
+ describe '#wiki_pages' do
28
+ specify do
29
+ expected = @raw.match(/Wiki \((\d+)\)/)[1].to_i
30
+ expected.should be > 50
31
+ subject.wiki_pages.should == expected
32
+ end
33
+ end
34
+
35
+ specify do
36
+ subject.should_not have_issues
37
+ end
38
+
39
+ describe '#issues' do
40
+ specify do
41
+ subject.issues.should == nil
42
+ end
43
+ end
44
+
45
+ describe '#pull_requests' do
46
+ specify do
47
+ expected = @raw.match(/Pull Requests \((\d+)\)/)[1].to_i
48
+ subject.pull_requests.should == expected
49
+ end
50
+ end
51
+
52
+ describe '#contributors' do
53
+ specify do
54
+ expected = @raw.match(/(\d+) contributors/)[1].to_i
55
+ subject.contributors.length.should == expected
56
+ end
57
+ end
58
+
59
+ describe '#contributor_usernames' do
60
+ specify do
61
+ subject.contributor_usernames.should include('aslakhellesoy')
62
+ end
63
+ end
64
+
65
+ describe '#contributor_realnames' do
66
+ specify do
67
+ subject.contributor_realnames.should include('Iain Hecker', 'Elliot Crosby-McCullough', 'Aslak Hellesøy')
68
+ end
69
+
70
+ specify do
71
+ subject.contributor_realnames.length.should < subject.contributor_usernames.length
72
+ end
73
+ end
74
+
75
+ describe '#contributor_names' do
76
+ specify do
77
+ subject.contributor_names.count.should == subject.contributors.count
78
+ end
79
+
80
+ specify do
81
+ subject.contributor_names.should include('Iain Hecker', 'Elliot Crosby-McCullough', 'Aslak Hellesøy')
82
+ end
83
+
84
+ specify do
85
+ subject.contributor_names.should include('marocchino')
86
+ end
87
+ end
88
+ end
89
+
90
+ context "initialized with colszowka/simplecov" do
91
+ before(:all) do
92
+ @metadata = GithubMetadata.new('colszowka', 'simplecov')
93
+ @raw = open("https://github.com/#{@metadata.user}/#{@metadata.repo}/contributors").read
94
+ end
95
+ subject { @metadata }
96
+
97
+ describe '#user' do
98
+ specify do
99
+ subject.user.should == 'colszowka'
100
+ end
101
+ end
102
+
103
+ describe '#repo' do
104
+ specify do
105
+ subject.repo.should == 'simplecov'
106
+ end
107
+ end
108
+
109
+ specify do
110
+ subject.should_not have_wiki
111
+ end
112
+
113
+ describe '#wiki_pages' do
114
+ specify do
115
+ subject.wiki_pages.should be nil
116
+ end
117
+ end
118
+
119
+ specify do
120
+ subject.should have_issues
121
+ end
122
+
123
+ describe '#issues' do
124
+ specify do
125
+ expected = @raw.match(/Issues \((\d+)\)/)[1].to_i
126
+ subject.issues.should == expected
127
+ end
128
+ end
129
+
130
+ describe '#pull_requests' do
131
+ specify do
132
+ subject.pull_requests.should be 0
133
+ end
134
+ end
135
+
136
+ describe '#contributors' do
137
+ specify do
138
+ expected = @raw.match(/(\d+) contributors/)[1].to_i
139
+ subject.contributors.length.should be expected
140
+ end
141
+
142
+ it 'should be all instance of Contributor' do
143
+ subject.contributors.should be_all {|c| c.instance_of?(GithubMetadata::Contributor)}
144
+ end
145
+ end
146
+
147
+ describe '#contributor_usernames' do
148
+ specify do
149
+ subject.contributor_usernames.should include('colszowka')
150
+ end
151
+ end
152
+
153
+ describe '#contributor_realnames' do
154
+ specify do
155
+ subject.contributor_realnames.should include('Christoph Olszowka')
156
+ end
157
+ end
158
+
159
+ describe '#contributor_names' do
160
+ specify do
161
+ subject.contributor_names.count.should be subject.contributors.count
162
+ end
163
+ specify do
164
+ subject.contributor_names.should include('Christoph Olszowka')
165
+ end
166
+ end
167
+ end
168
+
169
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+ require 'github_metadata'
6
+
7
+ RSpec.configure do |config|
8
+ # some (optional) config here
9
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: github_metadata
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Christoph Olszowka
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-01-04 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: nokogiri
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :runtime
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: rspec
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 2
43
+ - 0
44
+ - 0
45
+ version: 2.0.0
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: simplecov
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ type: :development
60
+ version_requirements: *id003
61
+ description: Extracts additional information like amount of committers, issues and wiki pages from Github repos
62
+ email:
63
+ - christoph at olszowka de
64
+ executables: []
65
+
66
+ extensions: []
67
+
68
+ extra_rdoc_files: []
69
+
70
+ files:
71
+ - .gitignore
72
+ - .rspec
73
+ - Gemfile
74
+ - Gemfile.lock
75
+ - LICENSE
76
+ - README.rdoc
77
+ - Rakefile
78
+ - github_metadata.gemspec
79
+ - lib/github_metadata.rb
80
+ - lib/github_metadata/version.rb
81
+ - spec/github_metadata_spec.rb
82
+ - spec/spec_helper.rb
83
+ has_rdoc: true
84
+ homepage: ""
85
+ licenses: []
86
+
87
+ post_install_message:
88
+ rdoc_options: []
89
+
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ segments:
106
+ - 0
107
+ version: "0"
108
+ requirements: []
109
+
110
+ rubyforge_project: github_metadata
111
+ rubygems_version: 1.3.7
112
+ signing_key:
113
+ specification_version: 3
114
+ summary: Extracts additional information from Github repos that isn't available via API
115
+ test_files:
116
+ - spec/github_metadata_spec.rb
117
+ - spec/spec_helper.rb