hubba 0.3.0 → 0.4.0

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: 990a81f63411ae5b97cd3ae1e6892cb8e8f788d3
4
- data.tar.gz: 1061e2b8963f97072cbdcedb5c6ba8c23ac3b691
3
+ metadata.gz: e3e04406b046b751a5eb400e8955417ae99498e7
4
+ data.tar.gz: 57752bfd47aea766d3db5c467659876216a644a0
5
5
  SHA512:
6
- metadata.gz: 05efa27d809de02a2e5582abe3c0d9b8f70629246d6d973d640b3fbb648365d7e0c6ecf32359837b06a83b2607d1ed4d9b5799af9c0f27d4244cce4dfe235a23
7
- data.tar.gz: 9ad616f2209a6f1c566b895d0e908b5a1cc5706d85626eb0519bb74117d4a6b4dc2f71c40eac2adb3e7caa1cfe4af33cfd1f7de57d96dd2d2390126a99e58899
6
+ metadata.gz: f96d7fa167b0e7cf8b685674aa80d19eca790ad237a9ea43cd40650d1c799448ce5827b009bb84b9d14c774b991693e1b0570735bf6573f64ed2c0a9e46c1c1f
7
+ data.tar.gz: 5cbdcd4a949763f19ba6275cec64cc1f3cfda6b05abe02950721befac8df17b1a5a1d64d1e41ae8048d23c06b93f41436d69bde91338e81313aa6e19af89236a
@@ -11,6 +11,11 @@ lib/hubba/version.rb
11
11
  test/cache/users~geraldb~orgs.json
12
12
  test/cache/users~geraldb~repos.json
13
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
14
18
  test/test_cache.rb
15
19
  test/test_config.rb
16
20
  test/test_stats.rb
21
+ test/test_stats_tmp.rb
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ 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
11
  self.urls = ['https://github.com/gittiscripts/hubba']
@@ -14,37 +14,156 @@ module Hubba
14
14
  @data['full_name'] = full_name # e.g. poole/hyde etc.
15
15
  end
16
16
 
17
- def full_name() @data['full_name']; end
18
17
 
19
- def created_at() @data['created_at']; end
20
- def updated_at() @data['updated_at']; end
21
- def pushed_at() @data['pushed_at']; end
18
+ def full_name() @full_name ||= @data['full_name']; end
22
19
 
23
- def history() @data['history']; end
20
+ ## note: return datetime objects (NOT strings); if not present/available return nil/null
21
+ def created_at() @created_at ||= @data['created_at'] ? DateTime.strptime( @data['created_at'], '%Y-%m-%dT%H:%M:%S') : nil; end
22
+ def updated_at() @updated_at ||= @data['updated_at'] ? DateTime.strptime( @data['updated_at'], '%Y-%m-%dT%H:%M:%S') : nil; end
23
+ def pushed_at() @pushed_at ||= @data['pushed_at'] ? DateTime.strptime( @data['pushed_at'], '%Y-%m-%dT%H:%M:%S') : nil; end
24
24
 
25
+ def history() @history ||= @data['history'] ? build_history( @data['history'] ) : nil; end
25
26
 
26
27
  def size
27
28
  # size of repo in kb (as reported by github api)
28
- @data['size'] || 0 ## return 0 if not found - why? why not? (return nil - why? why not??)
29
+ @size ||= @data['size'] || 0 ## return 0 if not found - why? why not? (return nil - why? why not??)
29
30
  end
30
31
 
31
32
  def stars
32
33
  ## return last stargazers_count entry (as number; 0 if not found)
33
- t1 = 0
34
+ @stars ||= history ? history[0].stars : 0
35
+ end
36
+
37
+ def reset_cache
38
+ ## reset (invalidate) cached values from data hash
39
+ ## use after reading or fetching
40
+ @full_name = nil
41
+ @created_at = @updated_at = @pushed_at = nil
42
+ @history = nil
43
+ @size = nil
44
+ @stars = nil
45
+ end
46
+
47
+
48
+ ########
49
+ ## build history items (structs)
50
+
51
+ class HistoryItem
52
+
53
+ attr_reader :date, :stars ## read-only attributes
54
+ attr_accessor :prev, :next ## read/write attributes (for double linked list/nodes/items)
55
+
56
+ def initialize( date:, stars: )
57
+ @date = date
58
+ @stars = stars
59
+ end
60
+
61
+ ## link items (append item at the end/tail)
62
+ def append( item )
63
+ @next = item
64
+ item.prev = self
65
+ end
66
+
67
+ def diff_days
68
+ if @next
69
+ ## note: use jd=julian days for calculation
70
+ @date.jd - @next.date.jd
71
+ else
72
+ nil ## last item (tail)
73
+ end
74
+ end
75
+
76
+ def diff_stars
77
+ if @next
78
+ @stars - @next.stars
79
+ else
80
+ nil ## last item (tail)
81
+ end
82
+ end
83
+ end ## class HistoryItem
84
+
85
+
86
+ def build_history( timeseries )
87
+ items = []
88
+
89
+ keys = timeseries.keys.sort.reverse ## newest (latest) items first
90
+ keys.each do |key|
91
+ h = timeseries[ key ]
34
92
 
35
- if history
36
- history_keys = history.keys.sort.reverse
37
- ## todo/fix: for now assumes one entry per week
38
- ## simple case [0] and [1] for a week later
39
- ## check actual date - why? why not?
40
- stats_t1 = history_keys[0] ? history[ history_keys[0] ] : nil
41
- if stats_t1
42
- t1 = stats_t1['stargazers_count'] || 0
43
- end
44
- end
45
- t1
46
- end # method stars
93
+ item = HistoryItem.new(
94
+ date: Date.strptime( key, '%Y-%m-%d' ),
95
+ stars: h['stargazers_count'] || 0 )
47
96
 
97
+ ## link items
98
+ last_item = items[-1]
99
+ last_item.append( item ) if last_item ## if not nil? append (note first item has no prev item)
100
+
101
+ items << item
102
+ end
103
+
104
+ ## todo/check: return [] for empty items array (items.empty?) - why?? why not??
105
+ if items.empty?
106
+ nil
107
+ else
108
+ items
109
+ end
110
+ end ## method build_history
111
+
112
+
113
+
114
+ def calc_diff_stars( samples: 3, days: 30 )
115
+ ## samples: use n history item samples e.g. 3 samples
116
+ ## days e.g. 7 days (per week), 30 days (per month)
117
+
118
+ if history.nil?
119
+ nil ## todo/check: return 0.0 too - why? why not?
120
+ elsif history.size == 1
121
+ ## just one item; CANNOT calc diff; return zero
122
+ 0.0
123
+ else
124
+ idx = [history.size, samples].min ## calc last index
125
+ last = history[idx-1]
126
+ first = history[0]
127
+
128
+ diff_days = first.date.jd - last.date.jd
129
+ diff_stars = first.stars - last.stars
130
+
131
+ ## note: use factor 1000 for fixed integer division
132
+ ## converts to float at the end
133
+
134
+ ## todo: check for better way (convert to float upfront - why? why not?)
135
+
136
+ diff = (diff_stars * days * 1000) / diff_days
137
+ puts "diff=#{diff}:#{diff.class.name}" ## check if it's a float
138
+ (diff.to_f/1000.0)
139
+ end
140
+ end
141
+
142
+ def history_str
143
+ ## returns "pretty printed" history as string buffer
144
+ buf = ''
145
+ buf << "[#{history.size}]: "
146
+
147
+ history.each do |item|
148
+ buf << "#{item.stars}"
149
+
150
+ diff_stars = item.diff_stars
151
+ diff_days = item.diff_days
152
+ if diff_stars && diff_days ## note: last item has no diffs
153
+ if diff_stars > 0 || diff_stars < 0
154
+ if diff_stars > 0
155
+ buf << " (+#{diff_stars}"
156
+ else
157
+ buf << " (#{diff_stars}"
158
+ end
159
+ buf << " in #{diff_days}d) "
160
+ else ## diff_stars == 0
161
+ buf << " (#{diff_days}d) "
162
+ end
163
+ end
164
+ end
165
+ buf
166
+ end # method history_str
48
167
 
49
168
 
50
169
  ###############################
@@ -89,32 +208,39 @@ module Hubba
89
208
  }
90
209
 
91
210
  ## for now store only the latest commit (e.g. a single commit in an array)
92
- @data[ 'commits'] = [commit]
211
+ @data[ 'commits' ] = [commit]
93
212
 
94
213
  pp @data
214
+
215
+ reset_cache
216
+ self ## return self for (easy chaining)
95
217
  end
96
218
 
97
219
 
98
220
 
99
221
  def write( data_dir: './data' )
100
222
  basename = full_name.gsub( '/', '~' ) ## e.g. poole/hyde become poole~hyde
101
- puts "writing (saving) to #{basename}..."
223
+ puts "writing stats to #{basename}..."
102
224
  File.open( "#{data_dir}/#{basename}.json", 'w:utf-8' ) do |f|
103
225
  f.write JSON.pretty_generate( data )
104
226
  end
227
+ self ## return self for (easy chaining)
105
228
  end
106
229
 
107
- def read( data_dir: './data' ) ## note: use read instead of load (load is kind of keyword for loading code)
230
+
231
+ def read( data_dir: './data' )
108
232
  ## note: skip reading if file not present
109
233
  basename = full_name.gsub( '/', '~' ) ## e.g. poole/hyde become poole~hyde
110
234
  filename = "#{data_dir}/#{basename}.json"
111
235
  if File.exist?( filename )
112
- puts "reading (loading) from #{basename}..."
236
+ puts "reading stats from #{basename}..."
113
237
  json = File.open( filename, 'r:utf-8' ) { |file| file.read } ## todo/fix: use read_utf8
114
238
  @data = JSON.parse( json )
239
+ reset_cache
115
240
  else
116
- puts "skipping reading (loading) from #{basename} -- file not found"
241
+ puts "skipping reading stats from #{basename} -- file not found"
117
242
  end
243
+ self ## return self for (easy chaining)
118
244
  end
119
245
 
120
246
  end # class Stats
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Hubba
4
4
  MAJOR = 0 ## todo: namespace inside version or something - why? why not??
5
- MINOR = 3
5
+ MINOR = 4
6
6
  PATCH = 0
7
7
  VERSION = [MAJOR,MINOR,PATCH].join('.')
8
8
 
@@ -0,0 +1,21 @@
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
+ "committer": {
15
+ "date": "2018-01-29T19:02:39Z",
16
+ "name": "Frank Taillandier"
17
+ },
18
+ "message": "Release 💎 v2.3.0 (#195)"
19
+ }
20
+ ]
21
+ }
@@ -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
+ }
@@ -32,15 +32,14 @@ class TestCache < MiniTest::Test
32
32
  def test_cache
33
33
  orgs = @cache.get( '/users/geraldb/orgs' )
34
34
  assert_equal 4, orgs.size
35
-
35
+
36
36
  repos = @cache.get( '/users/geraldb/repos' )
37
37
  assert_equal 3, repos.size
38
38
  end # method test_cache
39
39
 
40
40
  def test_cache_miss
41
- assert_equal nil, @cache.get( '/test/hello' )
42
- assert_equal nil, @cache.get( '/test/hola' )
41
+ assert_nil @cache.get( '/test/hello' )
42
+ assert_nil @cache.get( '/test/hola' )
43
43
  end # method test_cache_miss
44
44
 
45
45
  end # class TestCache
46
-
@@ -10,31 +10,77 @@ require 'helper'
10
10
 
11
11
  class TestStats < MiniTest::Test
12
12
 
13
- def setup
14
- @gh = Hubba::Github.new( cache_dir: "#{Hubba.root}/test/cache" )
13
+ def test_awesome_blockchains
14
+
15
+ stats = Hubba::Stats.new( 'openblockchains/awesome-blockchains' )
16
+
17
+ assert_equal 0, stats.size
18
+ assert_equal 0, stats.stars
19
+ assert_nil stats.history
20
+
21
+ stats.read( data_dir: "#{Hubba.root}/test/stats" )
22
+
23
+ assert_equal 1620, stats.size
24
+ assert_equal 1526, stats.stars
25
+ assert_equal 1526, stats.history[0].stars
26
+ assert_equal 1411, stats.history[1].stars
27
+ assert_equal 1084, stats.history[2].stars
28
+ assert_equal 1084, stats.history[-1].stars
29
+ assert_equal 3, stats.history.size
30
+
31
+ assert_equal Date.new(2018, 2, 8 ), stats.history[0].date
32
+ assert_equal Date.new(2018, 1, 28 ), stats.history[1].date
33
+ assert_equal Date.new(2017, 12, 10 ), stats.history[2].date
34
+
35
+ assert_equal 11, stats.history[0].diff_days
36
+ assert_equal 49, stats.history[1].diff_days
37
+ assert_nil stats.history[2].diff_days
38
+
39
+ assert_equal 115, stats.history[0].diff_stars
40
+ assert_equal 327, stats.history[1].diff_stars
41
+ assert_nil stats.history[2].diff_stars
42
+
43
+ assert_equal 221.0, stats.calc_diff_stars ## defaults to samples: 3, days: 30
44
+ assert_equal 51.566, stats.calc_diff_stars( samples: 5, days: 7 )
45
+
46
+ pp stats.history_str ## pp history pretty printed to string (buffer)
15
47
  end
16
48
 
17
- def test_stats
18
- repos = [
19
- 'henrythemes/jekyll-starter-theme',
20
- 'poole/hyde',
21
- 'jekyll/minima'
22
- ]
23
49
 
24
- repos.each do |repo|
25
- stats = Hubba::Stats.new( repo )
26
- stats.read( data_dir: './tmp' )
50
+ def test_factbook_json
51
+
52
+ stats = Hubba::Stats.new( 'opendatajson/factbook.json' )
53
+
54
+ assert_equal 0, stats.size
55
+ assert_equal 0, stats.stars
56
+ assert_nil stats.history
57
+
58
+ stats.read( data_dir: "#{Hubba.root}/test/stats" )
59
+
60
+ assert_equal 7355, stats.size
61
+ assert_equal 539, stats.stars
62
+ assert_equal 539, stats.history[0].stars
63
+ assert_equal 536, stats.history[1].stars
64
+ assert_equal 533, stats.history[2].stars
65
+ assert_equal 457, stats.history[-1].stars
66
+ assert_equal 7, stats.history.size
67
+
68
+ assert_equal Date.new(2018, 2, 8 ), stats.history[0].date
69
+ assert_equal Date.new(2018, 1, 28 ), stats.history[1].date
70
+ assert_equal Date.new(2017, 12, 10 ), stats.history[2].date
71
+
72
+ assert_equal 11, stats.history[0].diff_days
73
+ assert_equal 49, stats.history[1].diff_days
74
+ assert_nil stats.history[-1].diff_days
27
75
 
28
- puts "stars before fetch: #{stats.stars}"
29
- puts "size before fetch: #{stats.size} kb"
30
- stats.fetch( @gh )
31
- puts "stars after fetch: #{stats.stars}"
32
- puts "size after fetch: #{stats.size} kb"
76
+ assert_equal 3, stats.history[0].diff_stars
77
+ assert_equal 3, stats.history[1].diff_stars
78
+ assert_nil stats.history[-1].diff_stars
33
79
 
34
- stats.write( data_dir: './tmp' )
35
- end
80
+ assert_equal 3.0, stats.calc_diff_stars ## defaults to samples: 3, days: 30
81
+ assert_equal 1.012, stats.calc_diff_stars( samples: 5, days: 7 )
36
82
 
37
- assert true # for now everything ok if we get here
83
+ pp stats.history_str ## pp history pretty printed to string (buffer)
38
84
  end
39
85
 
40
86
  end # class TestStats
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+
3
+ ###
4
+ # to run use
5
+ # ruby -I ./lib -I ./test test/test_stats_tmp.rb
6
+
7
+
8
+ require 'helper'
9
+
10
+
11
+ class TestStatsTmp < MiniTest::Test
12
+
13
+ def setup
14
+ @gh = Hubba::Github.new( cache_dir: "#{Hubba.root}/test/cache" )
15
+ end
16
+
17
+ def test_stats
18
+ repos = [
19
+ 'henrythemes/jekyll-starter-theme',
20
+ 'poole/hyde',
21
+ 'jekyll/minima'
22
+ ]
23
+
24
+ repos.each do |repo|
25
+ stats = Hubba::Stats.new( repo )
26
+ stats.read( data_dir: './tmp' )
27
+
28
+ puts "stars before fetch: #{stats.stars}"
29
+ puts "size before fetch: #{stats.size} kb"
30
+
31
+ ## note/todo: enable for "live" online testing
32
+ ## stats.fetch( @gh )
33
+
34
+ puts "stars after fetch: #{stats.stars}"
35
+ puts "size after fetch: #{stats.size} kb"
36
+
37
+ stats.write( data_dir: './tmp' )
38
+ end
39
+
40
+ assert true # for now everything ok if we get here
41
+ end
42
+
43
+ end # class TestStatsTmp
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hubba
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-08 00:00:00.000000000 Z
11
+ date: 2018-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logutils
@@ -52,7 +52,7 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.16'
55
- description: hubba - (yet) another (lite) GitHub HTTP API client / library
55
+ description: hubba - (yet) another (lite) GitHub HTTP API client / library
56
56
  email: ruby-talk@ruby-lang.org
57
57
  executables: []
58
58
  extensions: []
@@ -74,9 +74,14 @@ files:
74
74
  - test/cache/users~geraldb~orgs.json
75
75
  - test/cache/users~geraldb~repos.json
76
76
  - test/helper.rb
77
+ - test/stats/jekyll~minima.json
78
+ - test/stats/openblockchains~awesome-blockchains.json
79
+ - test/stats/opendatajson~factbook.json.json
80
+ - test/stats/poole~hyde.json
77
81
  - test/test_cache.rb
78
82
  - test/test_config.rb
79
83
  - test/test_stats.rb
84
+ - test/test_stats_tmp.rb
80
85
  homepage: https://github.com/gittiscripts/hubba
81
86
  licenses:
82
87
  - Public Domain
@@ -102,5 +107,5 @@ rubyforge_project:
102
107
  rubygems_version: 2.5.2
103
108
  signing_key:
104
109
  specification_version: 4
105
- summary: hubba - (yet) another (lite) GitHub HTTP API client / library
110
+ summary: hubba - (yet) another (lite) GitHub HTTP API client / library
106
111
  test_files: []