hubba 0.1.2 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4a82adab1dd587bb3d9604b7ca60737747fe22f9
4
- data.tar.gz: 637d4e8a7714b3a6868e070cd064ed7a9f27d233
3
+ metadata.gz: 84577f7d76ee6b6e2b0c1dd2c747536bede539fe
4
+ data.tar.gz: 9f42b72e4402d148eaccbfd635f316161a50a857
5
5
  SHA512:
6
- metadata.gz: 2cef2397c74486671a6ac559e5ebe89dfe7d98efefe025c5f68694cbaa8809de279efe6bbc3aa7388426b01c198aea81214147a1f3d568ac8652d730a041e75f
7
- data.tar.gz: d5b460db26d282e941292bc7c1d030a7ee9b3d98502a39f12f659517a744f55913c85f7dc5b093d9494e7124ff7ba0ba17e9406805ccfab0a8ec82c55dc9be33
6
+ metadata.gz: 94e26559d4d814411a5537f879f58132c906ef7a3b2f7a61cc8f83d0e5f282b143d68f37a5462e5aef5e25daa86072b40e94c1b5177ab57023b80260f503b054
7
+ data.tar.gz: b9f03dba1f8861edbec94fb3411b2383dc1e12744387b9c6480b43a75ee6fa7331b57d81199a084cec742f0b35abf09167409d0328fd00a7da4fe3f15343a167
File without changes
@@ -1,4 +1,4 @@
1
- HISTORY.md
1
+ CHANGELOG.md
2
2
  Manifest.txt
3
3
  README.md
4
4
  Rakefile
@@ -6,9 +6,16 @@ lib/hubba.rb
6
6
  lib/hubba/cache.rb
7
7
  lib/hubba/client.rb
8
8
  lib/hubba/github.rb
9
+ lib/hubba/stats.rb
9
10
  lib/hubba/version.rb
10
11
  test/cache/users~geraldb~orgs.json
11
12
  test/cache/users~geraldb~repos.json
12
13
  test/helper.rb
14
+ test/stats/jekyll~minima.json
15
+ test/stats/openblockchains~awesome-blockchains.json
16
+ test/stats/opendatajson~factbook.json.json
17
+ test/stats/poole~hyde.json
13
18
  test/test_cache.rb
14
19
  test/test_config.rb
20
+ test/test_stats.rb
21
+ test/test_stats_tmp.rb
data/README.md CHANGED
@@ -1,20 +1,20 @@
1
- # hubba
2
-
3
- hubba gem - (yet) another (lite) GitHub HTTP API client / library
4
-
5
- * home :: [github.com/rubylibs/hubba](https://github.com/rubylibs/hubba)
6
- * bugs :: [github.com/rubylibs/hubba/issues](https://github.com/rubylibs/hubba/issues)
7
- * gem :: [rubygems.org/gems/hubba](https://rubygems.org/gems/hubba)
8
- * rdoc :: [rubydoc.info/gems/hubba](http://rubydoc.info/gems/hubba)
9
-
10
-
11
- ## Usage
12
-
13
- TBD
14
-
15
-
16
- ## License
17
-
18
- The `hubba` scripts are dedicated to the public domain.
19
- Use it as you please with no restrictions whatsoever.
20
-
1
+ # hubba
2
+
3
+ hubba gem - (yet) another (lite) GitHub HTTP API client / library
4
+
5
+ * home :: [github.com/rubycoco/git](https://github.com/rubycoco/git)
6
+ * bugs :: [github.com/rubycoco/git/issues](https://github.com/rubycoco/git/issues)
7
+ * gem :: [rubygems.org/gems/hubba](https://rubygems.org/gems/hubba)
8
+ * rdoc :: [rubydoc.info/gems/hubba](http://rubydoc.info/gems/hubba)
9
+
10
+
11
+ ## Usage
12
+
13
+ TBD
14
+
15
+
16
+
17
+ ## License
18
+
19
+ The `hubba` scripts are dedicated to the public domain.
20
+ Use it as you please with no restrictions whatsoever.
data/Rakefile CHANGED
@@ -5,26 +5,26 @@ Hoe.spec 'hubba' do
5
5
 
6
6
  self.version = Hubba::VERSION
7
7
 
8
- self.summary = 'hubba - (yet) another (lite) GitHub HTTP API client / library'
8
+ self.summary = 'hubba - (yet) another (lite) GitHub HTTP API client / library'
9
9
  self.description = summary
10
10
 
11
- self.urls = ['https://github.com/rubylibs/hubba']
11
+ self.urls = { home: 'https://github.com/rubycoco/git' }
12
12
 
13
13
  self.author = 'Gerald Bauer'
14
14
  self.email = 'ruby-talk@ruby-lang.org'
15
15
 
16
16
  # switch extension to .markdown for gihub formatting
17
17
  self.readme_file = 'README.md'
18
- self.history_file = 'HISTORY.md'
18
+ self.history_file = 'CHANGELOG.md'
19
19
 
20
20
  self.extra_deps = [
21
- ['logutils' ],
21
+ ['webclient', '>= 0.1.1']
22
22
  ]
23
23
 
24
24
  self.licenses = ['Public Domain']
25
25
 
26
26
  self.spec_extras = {
27
- required_ruby_version: '>= 1.9.2'
27
+ required_ruby_version: '>= 2.2.2'
28
28
  }
29
29
 
30
30
  end
@@ -1,23 +1,13 @@
1
- # encoding: utf-8
2
-
3
- require 'net/http'
4
- require "net/https"
5
- require 'uri'
6
-
7
- require 'pp'
8
- require 'json'
9
- require 'yaml'
10
-
11
-
12
- # 3rd party gems/libs
13
- require 'logutils'
1
+ # 3rd party (our own)
2
+ require 'webclient'
14
3
 
15
4
  # our own code
16
5
  require 'hubba/version' # note: let version always go first
17
6
  require 'hubba/cache'
18
7
  require 'hubba/client'
19
8
  require 'hubba/github'
9
+ require 'hubba/stats'
20
10
 
21
11
 
22
12
  # say hello
23
- puts Hubba.banner if defined?($RUBYLIBS_DEBUG)
13
+ puts Hubba.banner if defined?($RUBYCOCO_DEBUG)
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  module Hubba
4
2
 
5
3
  class Cache ## lets you work with GitHub api "offline" using just a local cache of stored json
@@ -14,7 +12,7 @@ class Cache ## lets you work with GitHub api "offline" using just a local ca
14
12
  basename = request_uri_to_basename( request_uri )
15
13
  path = "#{@dir}/#{basename}.json"
16
14
  if File.exist?( path )
17
- text = File.read( path ) ## todo/fix: use File.read_utf8
15
+ text = File.open( path, 'r:utf-8') { |f| f.read }
18
16
  json = JSON.parse( text )
19
17
  json
20
18
  else
@@ -32,8 +30,8 @@ class Cache ## lets you work with GitHub api "offline" using just a local ca
32
30
  data = obj # assume Hash or Array -- todo: add support for String - why? why not??
33
31
  end
34
32
 
35
- File.open( path, 'w' ) do |f|
36
- f.write JSON.pretty_generate( data )
33
+ File.open( path, 'w:utf-8' ) do |f|
34
+ f.write( JSON.pretty_generate( data ))
37
35
  end
38
36
  end
39
37
 
@@ -42,6 +40,7 @@ class Cache ## lets you work with GitHub api "offline" using just a local ca
42
40
  ## 1) cut off leading /
43
41
  ## 2) convert / to ~
44
42
  ## 3) remove (optional) query string (for now) - why? why not?
43
+ ## e.g. /users/#{name}/orgs?per_page=100 or such
45
44
  ##
46
45
  ## e.g.
47
46
  ## '/users/geraldb' => 'users~geraldb',
@@ -1,53 +1,76 @@
1
- # encoding: utf-8
2
-
3
1
  module Hubba
4
2
 
5
3
 
6
4
  class Client
7
5
 
8
- def initialize( user: nil, password: nil )
9
- uri = URI.parse( "https://api.github.com" )
10
- @http = Net::HTTP.new(uri.host, uri.port)
11
- @http.use_ssl = true
12
- @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
6
+ BASE_URL = 'https://api.github.com'
7
+
8
+
9
+ def initialize( token: nil,
10
+ user: nil, password: nil )
11
+ ## add support for (personal access) token
12
+ @token = token
13
13
 
14
14
  ## add support for basic auth - defaults to no auth (nil/nil)
15
+ ## remove - deprecated (use token) - why? why not?
15
16
  @user = user ## use login like Oktokit - why? why not?
16
17
  @password = password
17
18
  end # method initialize
18
19
 
20
+
21
+
19
22
  def get( request_uri )
23
+ ###
24
+ # e.g. /users/geraldb
25
+ # /users/geraldb/repos
26
+
20
27
  puts "GET #{request_uri}"
28
+ url = "#{BASE_URL}/#{request_uri}"
21
29
 
22
- req = Net::HTTP::Get.new( request_uri )
23
- ## req = Net::HTTP::Get.new( "/users/geraldb" )
24
- ## req = Net::HTTP::Get.new( "/users/geraldb/repos" )
25
- req["User-Agent"] = "ruby/hubba" ## required by GitHub API
26
- req["Accept" ] = "application/vnd.github.v3+json" ## recommend by GitHub API
30
+ headers = {}
31
+ headers['User-Agent'] = 'ruby/hubba' ## required by GitHub API
32
+ headers['Accept'] = 'application/vnd.github.v3+json' ## recommend by GitHub API
27
33
 
34
+ auth = []
28
35
  ## check if credentials (user/password) present - if yes, use basic auth
29
- if @user && @password
36
+ if @token
37
+ puts " using (personal access) token - starting with: #{@token[0..6]}**********"
38
+ headers['Authorization'] = "token #{@token}"
39
+ ## token works like:
40
+ ## curl -H 'Authorization: token my_access_token' https://api.github.com/user/repos
41
+ elsif @user && @password
30
42
  puts " using basic auth - user: #{@user}, password: ***"
31
- req.basic_auth( @user, @password )
43
+ ## use credential auth "tuple" (that is, array with two string items) for now
44
+ ## or use Webclient::HttpBasicAuth or something - why? why not?
45
+ auth = [@user, @password]
46
+ # req.basic_auth( @user, @password )
47
+ else
48
+ puts " using no credentials (no token, no user/password)"
32
49
  end
33
50
 
34
- res = @http.request(req)
51
+ res = Webclient.get( url,
52
+ headers: headers,
53
+ auth: auth )
35
54
 
36
55
  # Get specific header
37
56
  # response["content-type"]
38
57
  # => "text/html; charset=UTF-8"
39
58
 
40
59
  # Iterate all response headers.
41
- res.each_header do |key, value|
42
- p "#{key} => #{value}"
60
+ res.headers.each do |key, value|
61
+ puts "#{key} => #{value}"
43
62
  end
44
63
  # => "location => http://www.google.com/"
45
64
  # => "content-type => text/html; charset=UTF-8"
46
65
  # ...
47
66
 
48
- json = JSON.parse( res.body )
49
- ## pp json
50
- json
67
+ if res.status.ok?
68
+ res.json
69
+ else
70
+ puts "!! HTTP ERROR: #{res.status.code} #{res.status.message}:"
71
+ pp res.raw
72
+ exit 1
73
+ end
51
74
  end # methdo get
52
75
 
53
76
  end ## class Client
@@ -1,13 +1,15 @@
1
- # encoding: utf-8
2
-
3
1
  module Hubba
4
2
 
5
3
  class Configuration
4
+ attr_accessor :token
5
+
6
6
  attr_accessor :user
7
7
  attr_accessor :password
8
8
 
9
9
  def initialize
10
10
  # try default setup via ENV variables
11
+ @token = ENV[ 'HUBBA_TOKEN' ]
12
+
11
13
  @user = ENV[ 'HUBBA_USER' ] ## use HUBBA_LOGIN - why? why not?
12
14
  @password = ENV[ 'HUBBA_PASSWORD' ]
13
15
  end
@@ -15,6 +17,8 @@ end
15
17
 
16
18
  ## lets you use
17
19
  ## Hubba.configure do |config|
20
+ ## config.token = 'secret'
21
+ ## #-or-
18
22
  ## config.user = 'testdada'
19
23
  ## config.password = 'secret'
20
24
  ## end
@@ -61,8 +65,16 @@ class Github
61
65
 
62
66
  def initialize( cache_dir: './cache' )
63
67
  @cache = Cache.new( cache_dir )
64
- @client = Client.new( user: Hubba.configuration.user,
65
- password: Hubba.configuration.password )
68
+
69
+ @client = if Hubba.configuration.token
70
+ Client.new( token: Hubba.configuration.token )
71
+ elsif Hubba.configuration.user &&
72
+ Hubba.configuration.password
73
+ Client.new( user: Hubba.configuration.user,
74
+ password: Hubba.configuration.password )
75
+ else
76
+ Client.new
77
+ end
66
78
 
67
79
  @offline = false
68
80
  end
@@ -104,6 +116,16 @@ def org_repos( name )
104
116
  end
105
117
 
106
118
 
119
+
120
+ def repo( full_name ) ## full_name (handle) e.g. henrythemes/jekyll-starter-theme
121
+ Resource.new( get "/repos/#{full_name}" )
122
+ end
123
+
124
+ def repo_commits( full_name )
125
+ Resource.new( get "/repos/#{full_name}/commits" )
126
+ end
127
+
128
+
107
129
  private
108
130
  def get( request_uri )
109
131
  if offline?
@@ -0,0 +1,301 @@
1
+ module Hubba
2
+
3
+ ####
4
+ # keep track of repo stats over time (with history hash)
5
+
6
+ class Stats ## todo/check: rename to GithubRepoStats or RepoStats - why? why not?
7
+
8
+ attr_reader :data
9
+
10
+ def initialize( full_name )
11
+ @data = {}
12
+ @data['full_name'] = full_name # e.g. poole/hyde etc.
13
+ end
14
+
15
+
16
+ def full_name() @full_name ||= @data['full_name']; end
17
+
18
+ ## note: return datetime objects (NOT strings); if not present/available return nil/null
19
+ def created_at() @created_at ||= @data['created_at'] ? DateTime.strptime( @data['created_at'], '%Y-%m-%dT%H:%M:%S') : nil; end
20
+ def updated_at() @updated_at ||= @data['updated_at'] ? DateTime.strptime( @data['updated_at'], '%Y-%m-%dT%H:%M:%S') : nil; end
21
+ def pushed_at() @pushed_at ||= @data['pushed_at'] ? DateTime.strptime( @data['pushed_at'], '%Y-%m-%dT%H:%M:%S') : nil; end
22
+
23
+ ## date (only) versions
24
+ def created() @created ||= @data['created_at'] ? Date.strptime( @data['created_at'], '%Y-%m-%d') : nil; end
25
+ def updated() @updated ||= @data['updated_at'] ? Date.strptime( @data['updated_at'], '%Y-%m-%d') : nil; end
26
+ def pushed() @pushed ||= @data['pushed_at'] ? Date.strptime( @data['pushed_at'], '%Y-%m-%d') : nil; end
27
+
28
+
29
+
30
+ def history() @history ||= @data['history'] ? build_history( @data['history'] ) : nil; end
31
+
32
+ def size
33
+ # size of repo in kb (as reported by github api)
34
+ @size ||= @data['size'] || 0 ## return 0 if not found - why? why not? (return nil - why? why not??)
35
+ end
36
+
37
+ def stars
38
+ ## return last stargazers_count entry (as number; 0 if not found)
39
+ @stars ||= history ? history[0].stars : 0
40
+ end
41
+
42
+
43
+ def commits() @data['commits']; end
44
+
45
+ def last_commit() ## convenience shortcut; get first/last commit (use [0]) or nil
46
+ if @data['commits'] && @data['commits'][0]
47
+ @data['commits'][0]
48
+ else
49
+ nil
50
+ end
51
+ end
52
+
53
+ def committed() ## last commit date (from author NOT committer)
54
+ @committed ||= last_commit ? Date.strptime( last_commit['author']['date'], '%Y-%m-%d') : nil
55
+ end
56
+
57
+ def committed_at() ## last commit date (from author NOT committer)
58
+ @committed_at ||= last_commit ? DateTime.strptime( last_commit['author']['date'], '%Y-%m-%dT%H:%M:%S') : nil
59
+ end
60
+
61
+
62
+ def last_commit_message() ## convenience shortcut; last commit message
63
+ h = last_commit
64
+
65
+ committer_name = h['committer']['name']
66
+ author_name = h['author']['name']
67
+ message = h['message']
68
+
69
+ buf = ""
70
+ buf << message
71
+ buf << " by #{author_name}"
72
+
73
+ if committer_name != author_name
74
+ buf << " w/ #{committer_name}"
75
+ end
76
+ end # method commit_message
77
+
78
+
79
+
80
+ def reset_cache
81
+ ## reset (invalidate) cached values from data hash
82
+ ## use after reading or fetching
83
+ @full_name = nil
84
+ @created_at = @updated_at = @pushed_at = nil
85
+ @created = @updated = @pused = nil
86
+ @history = nil
87
+ @size = nil
88
+ @stars = nil
89
+
90
+ @committed_at = nil
91
+ @committed = nil
92
+ end
93
+
94
+
95
+ ########
96
+ ## build history items (structs)
97
+
98
+ class HistoryItem
99
+
100
+ attr_reader :date, :stars ## read-only attributes
101
+ attr_accessor :prev, :next ## read/write attributes (for double linked list/nodes/items)
102
+
103
+ def initialize( date:, stars: )
104
+ @date = date
105
+ @stars = stars
106
+ @next = nil
107
+ end
108
+
109
+ ## link items (append item at the end/tail)
110
+ def append( item )
111
+ @next = item
112
+ item.prev = self
113
+ end
114
+
115
+ def diff_days
116
+ if @next
117
+ ## note: use jd=julian days for calculation
118
+ @date.jd - @next.date.jd
119
+ else
120
+ nil ## last item (tail)
121
+ end
122
+ end
123
+
124
+ def diff_stars
125
+ if @next
126
+ @stars - @next.stars
127
+ else
128
+ nil ## last item (tail)
129
+ end
130
+ end
131
+ end ## class HistoryItem
132
+
133
+
134
+ def build_history( timeseries )
135
+ items = []
136
+
137
+ keys = timeseries.keys.sort.reverse ## newest (latest) items first
138
+ keys.each do |key|
139
+ h = timeseries[ key ]
140
+
141
+ item = HistoryItem.new(
142
+ date: Date.strptime( key, '%Y-%m-%d' ),
143
+ stars: h['stargazers_count'] || 0 )
144
+
145
+ ## link items
146
+ last_item = items[-1]
147
+ last_item.append( item ) if last_item ## if not nil? append (note first item has no prev item)
148
+
149
+ items << item
150
+ end
151
+
152
+ ## todo/check: return [] for empty items array (items.empty?) - why?? why not??
153
+ if items.empty?
154
+ nil
155
+ else
156
+ items
157
+ end
158
+ end ## method build_history
159
+
160
+
161
+
162
+ def calc_diff_stars( samples: 3, days: 30 )
163
+ ## samples: use n history item samples e.g. 3 samples
164
+ ## days e.g. 7 days (per week), 30 days (per month)
165
+
166
+ if history.nil?
167
+ nil ## todo/check: return 0.0 too - why? why not?
168
+ elsif history.size == 1
169
+ ## just one item; CANNOT calc diff; return zero
170
+ 0.0
171
+ else
172
+ idx = [history.size, samples].min ## calc last index
173
+ last = history[idx-1]
174
+ first = history[0]
175
+
176
+ diff_days = first.date.jd - last.date.jd
177
+ diff_stars = first.stars - last.stars
178
+
179
+ ## note: use factor 1000 for fixed integer division
180
+ ## converts to float at the end
181
+
182
+ ## todo: check for better way (convert to float upfront - why? why not?)
183
+
184
+ diff = (diff_stars * days * 1000) / diff_days
185
+ puts "diff=#{diff}:#{diff.class.name}" ## check if it's a float
186
+ (diff.to_f/1000.0)
187
+ end
188
+ end
189
+
190
+ def history_str
191
+ ## returns "pretty printed" history as string buffer
192
+ buf = ''
193
+ buf << "[#{history.size}]: "
194
+
195
+ history.each do |item|
196
+ buf << "#{item.stars}"
197
+
198
+ diff_stars = item.diff_stars
199
+ diff_days = item.diff_days
200
+ if diff_stars && diff_days ## note: last item has no diffs
201
+ if diff_stars > 0 || diff_stars < 0
202
+ if diff_stars > 0
203
+ buf << " (+#{diff_stars}"
204
+ else
205
+ buf << " (#{diff_stars}"
206
+ end
207
+ buf << " in #{diff_days}d) "
208
+ else ## diff_stars == 0
209
+ buf << " (#{diff_days}d) "
210
+ end
211
+ end
212
+ end
213
+ buf
214
+ end # method history_str
215
+
216
+
217
+ ###############################
218
+ ## fetch / read / write methods
219
+
220
+ def fetch( gh ) ## update stats / fetch data from github via api
221
+ puts "fetching #{full_name}..."
222
+ repo = gh.repo( full_name )
223
+
224
+ ## e.g. 2015-05-11T20:21:43Z
225
+ ## puts Time.iso8601( repo.data['created_at'] )
226
+ @data['created_at'] = repo.data['created_at']
227
+ @data['updated_at'] = repo.data['updated_at']
228
+ @data['pushed_at'] = repo.data['pushed_at']
229
+
230
+ @data['size'] = repo.data['size'] # size in kb (kilobyte)
231
+
232
+ rec = {}
233
+
234
+ puts "stargazers_count"
235
+ puts repo.data['stargazers_count']
236
+ rec['stargazers_count'] = repo.data['stargazers_count']
237
+
238
+ today = Date.today.strftime( '%Y-%m-%d' ) ## e.g. 2016-09-27
239
+ puts "add record #{today} to history..."
240
+ pp rec # check if stargazers_count is a number (NOT a string)
241
+
242
+ @data[ 'history' ] ||= {}
243
+ @data[ 'history' ][ today ] = rec
244
+
245
+ ##########################
246
+ ## also check / keep track of (latest) commit
247
+ commits = gh.repo_commits( full_name )
248
+ puts "last commit/update:"
249
+ ## pp commits
250
+ commit = {
251
+ 'committer' => {
252
+ 'date' => commits.data[0]['commit']['committer']['date'],
253
+ 'name' => commits.data[0]['commit']['committer']['name']
254
+ },
255
+ 'author' => {
256
+ 'date' => commits.data[0]['commit']['author']['date'],
257
+ 'name' => commits.data[0]['commit']['author']['name']
258
+ },
259
+ 'message' => commits.data[0]['commit']['message']
260
+ }
261
+
262
+ ## for now store only the latest commit (e.g. a single commit in an array)
263
+ @data[ 'commits' ] = [commit]
264
+
265
+ pp @data
266
+
267
+ reset_cache
268
+ self ## return self for (easy chaining)
269
+ end
270
+
271
+
272
+
273
+ def write( data_dir: './data' )
274
+ basename = full_name.gsub( '/', '~' ) ## e.g. poole/hyde become poole~hyde
275
+ puts "writing stats to #{basename}..."
276
+ File.open( "#{data_dir}/#{basename}.json", 'w:utf-8' ) do |f|
277
+ f.write JSON.pretty_generate( data )
278
+ end
279
+ self ## return self for (easy chaining)
280
+ end
281
+
282
+
283
+ def read( data_dir: './data' )
284
+ ## note: skip reading if file not present
285
+ basename = full_name.gsub( '/', '~' ) ## e.g. poole/hyde become poole~hyde
286
+ filename = "#{data_dir}/#{basename}.json"
287
+ if File.exist?( filename )
288
+ puts "reading stats from #{basename}..."
289
+ json = File.open( filename, 'r:utf-8' ) { |file| file.read } ## todo/fix: use read_utf8
290
+ @data = JSON.parse( json )
291
+ reset_cache
292
+ else
293
+ puts "skipping reading stats from #{basename} -- file not found"
294
+ end
295
+ self ## return self for (easy chaining)
296
+ end
297
+
298
+ end # class Stats
299
+
300
+
301
+ end # module Hubba
@@ -1,9 +1,7 @@
1
- # encoding: utf-8
2
-
3
1
  module Hubba
4
2
  MAJOR = 0 ## todo: namespace inside version or something - why? why not??
5
- MINOR = 1
6
- PATCH = 2
3
+ MINOR = 5
4
+ PATCH = 1
7
5
  VERSION = [MAJOR,MINOR,PATCH].join('.')
8
6
 
9
7
  def self.version
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  # minitest setup
4
2
  require 'minitest/autorun'
5
3
 
@@ -0,0 +1,25 @@
1
+ {
2
+ "full_name": "jekyll/minima",
3
+ "created_at": "2016-05-20T23:07:56Z",
4
+ "updated_at": "2018-02-11T16:13:33Z",
5
+ "pushed_at": "2018-02-07T22:14:11Z",
6
+ "size": 321,
7
+ "history": {
8
+ "2018-02-12": {
9
+ "stargazers_count": 717
10
+ }
11
+ },
12
+ "commits": [
13
+ {
14
+ "author": {
15
+ "name": "ashmaroli",
16
+ "date": "2018-02-21T19:35:59Z"
17
+ },
18
+ "committer": {
19
+ "name": "Frank Taillandier",
20
+ "date": "2018-02-21T19:35:59Z"
21
+ },
22
+ "message": "social icons should resolve baseurl properly (#201)"
23
+ }
24
+ ]
25
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "full_name": "openblockchains/awesome-blockchains",
3
+ "created_at": "2017-09-13T22:33:56Z",
4
+ "size": 1620,
5
+ "history": {
6
+ "2017-12-10": {
7
+ "stargazers_count": 1084
8
+ },
9
+ "2018-01-28": {
10
+ "stargazers_count": 1411
11
+ },
12
+ "2018-02-08": {
13
+ "stargazers_count": 1526
14
+ }
15
+ },
16
+ "commits": [
17
+ {
18
+ "committer": {
19
+ "date": "2018-02-08T09:33:28Z",
20
+ "name": "Gerald Bauer"
21
+ },
22
+ "message": "Update README.md\n\nJust a little typo cryto -> crypto."
23
+ }
24
+ ],
25
+ "updated_at": "2018-02-08T19:26:35Z",
26
+ "pushed_at": "2018-02-08T09:33:29Z"
27
+ }
@@ -0,0 +1,39 @@
1
+ {
2
+ "full_name": "opendatajson/factbook.json",
3
+ "created_at": "2014-07-12T12:43:52Z",
4
+ "history": {
5
+ "2017-02-11": {
6
+ "stargazers_count": 457
7
+ },
8
+ "2017-02-12": {
9
+ "stargazers_count": 457
10
+ },
11
+ "2017-06-18": {
12
+ "stargazers_count": 505
13
+ },
14
+ "2017-07-28": {
15
+ "stargazers_count": 512
16
+ },
17
+ "2017-12-10": {
18
+ "stargazers_count": 533
19
+ },
20
+ "2018-01-28": {
21
+ "stargazers_count": 536
22
+ },
23
+ "2018-02-08": {
24
+ "stargazers_count": 539
25
+ }
26
+ },
27
+ "commits": [
28
+ {
29
+ "committer": {
30
+ "date": "2017-03-29T17:23:29Z",
31
+ "name": "GitHub"
32
+ },
33
+ "message": "Update MONGO.md"
34
+ }
35
+ ],
36
+ "size": 7355,
37
+ "updated_at": "2018-02-01T12:35:19Z",
38
+ "pushed_at": "2017-03-29T17:23:30Z"
39
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "full_name": "poole/hyde",
3
+ "created_at": "2013-02-07T07:01:38Z",
4
+ "updated_at": "2018-02-12T05:44:07Z",
5
+ "pushed_at": "2018-01-14T02:41:16Z",
6
+ "size": 28428,
7
+ "history": {
8
+ "2018-02-12": {
9
+ "stargazers_count": 2125
10
+ }
11
+ },
12
+ "commits": [
13
+ {
14
+ "committer": {
15
+ "date": "2015-05-11T20:21:43Z",
16
+ "name": "Mark Otto"
17
+ },
18
+ "message": "Merge pull request #91 from pborreli/patch-1\n\nFixed typo"
19
+ }
20
+ ]
21
+ }
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  ###
4
2
  # to run use
5
3
  # ruby -I ./lib -I ./test test/test_cache.rb
@@ -32,15 +30,14 @@ class TestCache < MiniTest::Test
32
30
  def test_cache
33
31
  orgs = @cache.get( '/users/geraldb/orgs' )
34
32
  assert_equal 4, orgs.size
35
-
33
+
36
34
  repos = @cache.get( '/users/geraldb/repos' )
37
35
  assert_equal 3, repos.size
38
36
  end # method test_cache
39
37
 
40
38
  def test_cache_miss
41
- assert_equal nil, @cache.get( '/test/hello' )
42
- assert_equal nil, @cache.get( '/test/hola' )
39
+ assert_nil @cache.get( '/test/hello' )
40
+ assert_nil @cache.get( '/test/hola' )
43
41
  end # method test_cache_miss
44
42
 
45
43
  end # class TestCache
46
-
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  ###
4
2
  # to run use
5
3
  # ruby -I ./lib -I ./test test/test_config.rb
@@ -0,0 +1,122 @@
1
+ ###
2
+ # to run use
3
+ # ruby -I ./lib -I ./test test/test_stats.rb
4
+
5
+
6
+ require 'helper'
7
+
8
+
9
+ class TestStats < MiniTest::Test
10
+
11
+
12
+ def test_jekyll_minima
13
+
14
+ stats = Hubba::Stats.new( 'jekyll/minima' )
15
+
16
+ assert_equal 0, stats.size
17
+ assert_equal 0, stats.stars
18
+ assert_nil stats.history
19
+
20
+ stats.read( data_dir: "#{Hubba.root}/test/stats" )
21
+
22
+ assert_equal 321, stats.size
23
+ assert_equal 717, stats.stars
24
+ assert_equal 717, stats.history[0].stars
25
+ assert_equal 1, stats.history.size
26
+
27
+ assert_equal Date.new(2018, 2, 12 ), stats.history[0].date
28
+
29
+ assert_nil stats.history[0].diff_days
30
+
31
+ assert_equal Date.new(2018, 2, 21 ), stats.committed
32
+ assert_equal Date.new(2016, 5, 20 ), stats.created
33
+ assert_equal Date.new(2018, 2, 11 ), stats.updated
34
+ assert_equal Date.new(2018, 2, 7 ), stats.pushed
35
+
36
+ assert_equal DateTime.new(2018, 2, 21, 19, 35, 59 ), stats.committed_at
37
+ assert_equal DateTime.new(2016, 5, 20, 23, 7, 56 ), stats.created_at
38
+ assert_equal DateTime.new(2018, 2, 11, 16, 13, 33 ), stats.updated_at
39
+ assert_equal DateTime.new(2018, 2, 7, 22, 14, 11 ), stats.pushed_at
40
+
41
+
42
+ pp stats.last_commit
43
+ pp stats.last_commit_message
44
+ pp stats.history_str ## pp history pretty printed to string (buffer)
45
+ end
46
+
47
+
48
+
49
+ def test_awesome_blockchains
50
+
51
+ stats = Hubba::Stats.new( 'openblockchains/awesome-blockchains' )
52
+
53
+ assert_equal 0, stats.size
54
+ assert_equal 0, stats.stars
55
+ assert_nil stats.history
56
+
57
+ stats.read( data_dir: "#{Hubba.root}/test/stats" )
58
+
59
+ assert_equal 1620, stats.size
60
+ assert_equal 1526, stats.stars
61
+ assert_equal 1526, stats.history[0].stars
62
+ assert_equal 1411, stats.history[1].stars
63
+ assert_equal 1084, stats.history[2].stars
64
+ assert_equal 1084, stats.history[-1].stars
65
+ assert_equal 3, stats.history.size
66
+
67
+ assert_equal Date.new(2018, 2, 8 ), stats.history[0].date
68
+ assert_equal Date.new(2018, 1, 28 ), stats.history[1].date
69
+ assert_equal Date.new(2017, 12, 10 ), stats.history[2].date
70
+
71
+ assert_equal 11, stats.history[0].diff_days
72
+ assert_equal 49, stats.history[1].diff_days
73
+ assert_nil stats.history[2].diff_days
74
+
75
+ assert_equal 115, stats.history[0].diff_stars
76
+ assert_equal 327, stats.history[1].diff_stars
77
+ assert_nil stats.history[2].diff_stars
78
+
79
+ assert_equal 221.0, stats.calc_diff_stars ## defaults to samples: 3, days: 30
80
+ assert_equal 51.566, stats.calc_diff_stars( samples: 5, days: 7 )
81
+
82
+ pp stats.history_str ## pp history pretty printed to string (buffer)
83
+ end
84
+
85
+
86
+ def test_factbook_json
87
+
88
+ stats = Hubba::Stats.new( 'opendatajson/factbook.json' )
89
+
90
+ assert_equal 0, stats.size
91
+ assert_equal 0, stats.stars
92
+ assert_nil stats.history
93
+
94
+ stats.read( data_dir: "#{Hubba.root}/test/stats" )
95
+
96
+ assert_equal 7355, stats.size
97
+ assert_equal 539, stats.stars
98
+ assert_equal 539, stats.history[0].stars
99
+ assert_equal 536, stats.history[1].stars
100
+ assert_equal 533, stats.history[2].stars
101
+ assert_equal 457, stats.history[-1].stars
102
+ assert_equal 7, stats.history.size
103
+
104
+ assert_equal Date.new(2018, 2, 8 ), stats.history[0].date
105
+ assert_equal Date.new(2018, 1, 28 ), stats.history[1].date
106
+ assert_equal Date.new(2017, 12, 10 ), stats.history[2].date
107
+
108
+ assert_equal 11, stats.history[0].diff_days
109
+ assert_equal 49, stats.history[1].diff_days
110
+ assert_nil stats.history[-1].diff_days
111
+
112
+ assert_equal 3, stats.history[0].diff_stars
113
+ assert_equal 3, stats.history[1].diff_stars
114
+ assert_nil stats.history[-1].diff_stars
115
+
116
+ assert_equal 3.0, stats.calc_diff_stars ## defaults to samples: 3, days: 30
117
+ assert_equal 1.012, stats.calc_diff_stars( samples: 5, days: 7 )
118
+
119
+ pp stats.history_str ## pp history pretty printed to string (buffer)
120
+ end
121
+
122
+ end # class TestStats
@@ -0,0 +1,41 @@
1
+ ###
2
+ # to run use
3
+ # ruby -I ./lib -I ./test test/test_stats_tmp.rb
4
+
5
+
6
+ require 'helper'
7
+
8
+
9
+ class TestStatsTmp < MiniTest::Test
10
+
11
+ def setup
12
+ @gh = Hubba::Github.new( cache_dir: "#{Hubba.root}/test/cache" )
13
+ end
14
+
15
+ def test_stats
16
+ repos = [
17
+ 'poole/hyde',
18
+ 'jekyll/minima'
19
+ ]
20
+
21
+ repos.each do |repo|
22
+ stats = Hubba::Stats.new( repo )
23
+ # stats.read( data_dir: './tmp' )
24
+ stats.read( data_dir: "#{Hubba.root}/test/stats" )
25
+
26
+ puts "stars before fetch: #{stats.stars}"
27
+ puts "size before fetch: #{stats.size} kb"
28
+
29
+ ## note/todo: enable for "live" online testing
30
+ ## stats.fetch( @gh )
31
+
32
+ puts "stars after fetch: #{stats.stars}"
33
+ puts "size after fetch: #{stats.size} kb"
34
+
35
+ stats.write( data_dir: './tmp' )
36
+ end
37
+
38
+ assert true # for now everything ok if we get here
39
+ end
40
+
41
+ end # class TestStatsTmp
metadata CHANGED
@@ -1,67 +1,73 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hubba
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-17 00:00:00.000000000 Z
11
+ date: 2020-10-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: logutils
14
+ name: webclient
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 0.1.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: 0.1.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rdoc
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '4.0'
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '7'
34
37
  type: :development
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
- - - "~>"
41
+ - - ">="
39
42
  - !ruby/object:Gem::Version
40
43
  version: '4.0'
44
+ - - "<"
45
+ - !ruby/object:Gem::Version
46
+ version: '7'
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: hoe
43
49
  requirement: !ruby/object:Gem::Requirement
44
50
  requirements:
45
51
  - - "~>"
46
52
  - !ruby/object:Gem::Version
47
- version: '3.14'
53
+ version: '3.22'
48
54
  type: :development
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
51
57
  requirements:
52
58
  - - "~>"
53
59
  - !ruby/object:Gem::Version
54
- version: '3.14'
55
- description: hubba - (yet) another (lite) GitHub HTTP API client / library
60
+ version: '3.22'
61
+ description: hubba - (yet) another (lite) GitHub HTTP API client / library
56
62
  email: ruby-talk@ruby-lang.org
57
63
  executables: []
58
64
  extensions: []
59
65
  extra_rdoc_files:
60
- - HISTORY.md
66
+ - CHANGELOG.md
61
67
  - Manifest.txt
62
68
  - README.md
63
69
  files:
64
- - HISTORY.md
70
+ - CHANGELOG.md
65
71
  - Manifest.txt
66
72
  - README.md
67
73
  - Rakefile
@@ -69,13 +75,20 @@ files:
69
75
  - lib/hubba/cache.rb
70
76
  - lib/hubba/client.rb
71
77
  - lib/hubba/github.rb
78
+ - lib/hubba/stats.rb
72
79
  - lib/hubba/version.rb
73
80
  - test/cache/users~geraldb~orgs.json
74
81
  - test/cache/users~geraldb~repos.json
75
82
  - test/helper.rb
83
+ - test/stats/jekyll~minima.json
84
+ - test/stats/openblockchains~awesome-blockchains.json
85
+ - test/stats/opendatajson~factbook.json.json
86
+ - test/stats/poole~hyde.json
76
87
  - test/test_cache.rb
77
88
  - test/test_config.rb
78
- homepage: https://github.com/rubylibs/hubba
89
+ - test/test_stats.rb
90
+ - test/test_stats_tmp.rb
91
+ homepage: https://github.com/rubycoco/git
79
92
  licenses:
80
93
  - Public Domain
81
94
  metadata: {}
@@ -89,7 +102,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
89
102
  requirements:
90
103
  - - ">="
91
104
  - !ruby/object:Gem::Version
92
- version: 1.9.2
105
+ version: 2.2.2
93
106
  required_rubygems_version: !ruby/object:Gem::Requirement
94
107
  requirements:
95
108
  - - ">="
@@ -97,8 +110,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
110
  version: '0'
98
111
  requirements: []
99
112
  rubyforge_project:
100
- rubygems_version: 2.2.3
113
+ rubygems_version: 2.5.2
101
114
  signing_key:
102
115
  specification_version: 4
103
- summary: hubba - (yet) another (lite) GitHub HTTP API client / library
116
+ summary: hubba - (yet) another (lite) GitHub HTTP API client / library
104
117
  test_files: []