gcstats 1.0.1 → 1.0.3
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.
- data/README.md +1 -1
- data/bin/gcstats +6 -7
- data/{lib → data}/gcstats/gcstats.css +0 -0
- data/{lib → data}/gcstats/gcstats.js +8 -6
- data/{lib → data}/gcstats/gcstats.rhtml +30 -16
- data/lib/gcstats/{mapping.rb → caches.rb} +0 -0
- data/lib/gcstats/helpers.rb +33 -49
- data/lib/gcstats/server.rb +37 -34
- data/lib/gcstats/version.rb +1 -1
- data/spec/fixtures/3627915.gpx +3321 -0
- data/spec/lib/caches_spec.rb +67 -0
- data/spec/lib/helpers_spec.rb +162 -0
- data/spec/lib/template_spec.rb +15 -0
- data/spec/spec_helper.rb +15 -0
- metadata +23 -15
- data/config.ru +0 -6
data/README.md
CHANGED
@@ -12,7 +12,7 @@ Also available online as a web app: <http://gcstats.heroku.com/>
|
|
12
12
|
To install, change directory to where you have extracted the gcstats source files and issue:
|
13
13
|
|
14
14
|
gem build gcstats.gemspec
|
15
|
-
gem install gcstats
|
15
|
+
gem install gcstats
|
16
16
|
|
17
17
|
## Use ##
|
18
18
|
|
data/bin/gcstats
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'rubygems'
|
4
3
|
require 'zip/zip'
|
5
|
-
require 'gcstats/
|
4
|
+
require 'gcstats/caches'
|
6
5
|
require 'gcstats/template'
|
7
6
|
|
8
7
|
in_fn, out_fn = ARGV[0..1]
|
@@ -25,18 +24,18 @@ if File.extname(in_fn) == '.zip'
|
|
25
24
|
end
|
26
25
|
}
|
27
26
|
else
|
28
|
-
data = File.read(in_fn)
|
27
|
+
data = (in_fn == '-') ? $stdin.read : File.read(in_fn)
|
29
28
|
out_fn ||= File.basename(in_fn, File.extname(in_fn)) + '.html'
|
30
29
|
end
|
31
30
|
|
32
|
-
|
31
|
+
datadir = File.join(File.dirname(__FILE__), '..', 'data', 'gcstats')
|
33
32
|
|
34
|
-
rhtml = File.read(File.join(
|
33
|
+
rhtml = File.read(File.join(datadir, 'gcstats.rhtml'))
|
35
34
|
caches = GCStats::Caches.from_xml(data)
|
36
35
|
data = {:caches => caches, :start_ts => start_ts}
|
37
36
|
html = GCStats::Template.new(rhtml, data).result
|
38
|
-
html.sub!('/* %css% */', "\n" + File.read(File.join(
|
39
|
-
html.sub!('/* %js% */', "\n" + File.read(File.join(
|
37
|
+
html.sub!('/* %css% */', "\n" + File.read(File.join(datadir, 'gcstats.css')))
|
38
|
+
html.sub!('/* %js% */', "\n" + File.read(File.join(datadir, 'gcstats.js')))
|
40
39
|
|
41
40
|
if ARGV[1].nil? && caches[0] && caches[0].logs[0]
|
42
41
|
out_fn = caches[0].logs[0].finder
|
File without changes
|
@@ -27,7 +27,7 @@ if (!GCStats) {
|
|
27
27
|
var total_row, row_max, total_col, col_max, inner_cells, table_max;
|
28
28
|
|
29
29
|
// total row
|
30
|
-
|
30
|
+
|
31
31
|
total_row = $(table).find('tr.total td');
|
32
32
|
|
33
33
|
row_max = total_row.slice(0, -1).map(function () {
|
@@ -69,10 +69,12 @@ if (!GCStats) {
|
|
69
69
|
};
|
70
70
|
|
71
71
|
$(document).ready(function () {
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
72
|
+
$('table.highlight:not(.square)').each(function () {
|
73
|
+
GCStats.highlight_table(this);
|
74
|
+
});
|
75
|
+
|
76
|
+
$('table.highlight.square').each(function () {
|
77
|
+
GCStats.highlight_square_table(this);
|
78
|
+
});
|
77
79
|
});
|
78
80
|
}
|
@@ -25,7 +25,7 @@
|
|
25
25
|
</tr>
|
26
26
|
<tr>
|
27
27
|
<th class="l">Archived</th>
|
28
|
-
<td><%= total_archived %></td>
|
28
|
+
<td><%= '%d (%s)' % [total_archived, format_percent(total_archived, total_finds)] %></td>
|
29
29
|
</tr>
|
30
30
|
<tr>
|
31
31
|
<th class="l">Caches/Day</th>
|
@@ -39,11 +39,25 @@
|
|
39
39
|
<th class="l">Most in one day</th>
|
40
40
|
<td><%= '%d (%s)' % [most_finds_in_a_day, most_finds_in_a_day_dates.join(', ')] %></td>
|
41
41
|
</tr>
|
42
|
+
<tr>
|
43
|
+
<th class="l">Oldest cache</th>
|
44
|
+
<td>
|
45
|
+
<a href="<%=h oldest_cache_found.url %>"><%=h oldest_cache_found.name %></a>
|
46
|
+
(<%=h oldest_cache_found.published.strftime('%Y-%m-%d') %>)
|
47
|
+
</td>
|
48
|
+
</tr>
|
49
|
+
<tr>
|
50
|
+
<th class="l">Newest cache</th>
|
51
|
+
<td>
|
52
|
+
<a href="<%=h newest_cache_found.url %>"><%=h newest_cache_found.name %></a>
|
53
|
+
(<%=h newest_cache_found.published.strftime('%Y-%m-%d') %>)
|
54
|
+
</td>
|
55
|
+
</tr>
|
42
56
|
</table>
|
43
57
|
<%# }}} %>
|
44
58
|
|
45
59
|
<%# {{{ finds by day of week %>
|
46
|
-
<table
|
60
|
+
<table class="highlight">
|
47
61
|
<caption>Finds by Day of Week</caption>
|
48
62
|
<tr>
|
49
63
|
<th>Day</th>
|
@@ -54,14 +68,14 @@
|
|
54
68
|
<tr>
|
55
69
|
<td><%= DAY_NAME[i] %></td>
|
56
70
|
<td class="finds r"><%= finds %></td>
|
57
|
-
<td class="r"><%=
|
71
|
+
<td class="r"><%= format_percent(finds, total_finds) %></td>
|
58
72
|
</tr>
|
59
73
|
<% } %>
|
60
74
|
</table>
|
61
75
|
<%# }}} %>
|
62
76
|
|
63
77
|
<%# {{{ finds by year %>
|
64
|
-
<table
|
78
|
+
<table class="highlight">
|
65
79
|
<caption>Finds by Year</caption>
|
66
80
|
<tr>
|
67
81
|
<th>Year</th>
|
@@ -72,7 +86,7 @@
|
|
72
86
|
<tr>
|
73
87
|
<td><%= year %></td>
|
74
88
|
<td class="finds r"><%= finds = finds_by_year[year] %></td>
|
75
|
-
<td class="r"><%=
|
89
|
+
<td class="r"><%= format_percent(finds, total_finds) %></td>
|
76
90
|
</tr>
|
77
91
|
<% } %>
|
78
92
|
</table>
|
@@ -90,7 +104,7 @@
|
|
90
104
|
<tr>
|
91
105
|
<td><%=h size %></td>
|
92
106
|
<td class="r"><%= finds %></td>
|
93
|
-
<td class="r"><%=
|
107
|
+
<td class="r"><%= format_percent(finds, total_finds) %></td>
|
94
108
|
</tr>
|
95
109
|
<% } %>
|
96
110
|
</table>
|
@@ -108,7 +122,7 @@
|
|
108
122
|
<tr>
|
109
123
|
<td><%=h type %></td>
|
110
124
|
<td class="r"><%= finds %></td>
|
111
|
-
<td class="r"><%=
|
125
|
+
<td class="r"><%= format_percent(finds, total_finds) %></td>
|
112
126
|
</tr>
|
113
127
|
<% } %>
|
114
128
|
</table>
|
@@ -126,14 +140,14 @@
|
|
126
140
|
<tr>
|
127
141
|
<td><%=h owner %></td>
|
128
142
|
<td class="r"><%= finds %></td>
|
129
|
-
<td class="r"><%=
|
143
|
+
<td class="r"><%= format_percent(finds, total_finds) %></td>
|
130
144
|
</tr>
|
131
145
|
<% } %>
|
132
146
|
</table>
|
133
147
|
<%# }}} %>
|
134
148
|
|
135
149
|
<%# {{{ difficulty/terrain combinations %>
|
136
|
-
<table
|
150
|
+
<table class="c highlight square">
|
137
151
|
<caption>Difficulty/Terrain Combinations</caption>
|
138
152
|
<tr>
|
139
153
|
<th>D/T</th>
|
@@ -162,7 +176,7 @@
|
|
162
176
|
<%# }}} %>
|
163
177
|
|
164
178
|
<%# {{{ month/day combinations %>
|
165
|
-
<table
|
179
|
+
<table class="c highlight square">
|
166
180
|
<caption>Month/Day Combinations</caption>
|
167
181
|
<tr>
|
168
182
|
<th>M/D</th>
|
@@ -198,11 +212,11 @@
|
|
198
212
|
<th>Finds</th>
|
199
213
|
<th>Percentage</th>
|
200
214
|
</tr>
|
201
|
-
<% finds_by_country.sort {|
|
215
|
+
<% finds_by_country.sort {|a, b| b[1] <=> a[1] }.each {|country, finds| %>
|
202
216
|
<tr>
|
203
217
|
<td><%=h country %></td>
|
204
218
|
<td class="r"><%= finds %></td>
|
205
|
-
<td class="r"><%=
|
219
|
+
<td class="r"><%= format_percent(finds, total_finds) %></td>
|
206
220
|
</tr>
|
207
221
|
<% } %>
|
208
222
|
</table>
|
@@ -222,12 +236,12 @@
|
|
222
236
|
<th>Total</th>
|
223
237
|
</tr>
|
224
238
|
<% country_finds = states.map {|s| s[1] }.sum %>
|
225
|
-
<% states.sort {|
|
239
|
+
<% states.sort {|a, b| b[1] <=> a[1] }.each {|state, finds| %>
|
226
240
|
<tr>
|
227
241
|
<td><%=h state %></td>
|
228
242
|
<td class="r"><%= finds %></td>
|
229
|
-
<td class="r"><%=
|
230
|
-
<td class="r"><%=
|
243
|
+
<td class="r"><%= format_percent(finds, country_finds) %></td>
|
244
|
+
<td class="r"><%= format_percent(finds, total_finds) %></td>
|
231
245
|
</tr>
|
232
246
|
<% } %>
|
233
247
|
</table>
|
@@ -235,7 +249,7 @@
|
|
235
249
|
<%# }}} %>
|
236
250
|
|
237
251
|
<%# {{{ finds by date %>
|
238
|
-
<table
|
252
|
+
<table class="highlight">
|
239
253
|
<caption>Finds by Date</caption>
|
240
254
|
<tr>
|
241
255
|
<th>Date</th>
|
File without changes
|
data/lib/gcstats/helpers.rb
CHANGED
@@ -22,7 +22,7 @@ module GCStats
|
|
22
22
|
def days_cached
|
23
23
|
@days_cached ||= begin
|
24
24
|
dates = finds_by_date.keys.sort
|
25
|
-
(dates
|
25
|
+
(dates.last - dates.first).to_i
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
@@ -40,15 +40,11 @@ module GCStats
|
|
40
40
|
|
41
41
|
def finds_by_date
|
42
42
|
@finds_by_date ||= begin
|
43
|
-
finds =
|
43
|
+
finds = Hash.new(0)
|
44
44
|
|
45
45
|
@caches.each {|cache|
|
46
46
|
cache.find_dates.each {|find_date|
|
47
|
-
|
48
|
-
finds[find_date] += 1
|
49
|
-
rescue
|
50
|
-
finds[find_date] = 1
|
51
|
-
end
|
47
|
+
finds[find_date] += 1
|
52
48
|
}
|
53
49
|
}
|
54
50
|
|
@@ -66,11 +62,7 @@ module GCStats
|
|
66
62
|
wday = date.wday
|
67
63
|
end
|
68
64
|
|
69
|
-
|
70
|
-
finds[wday] += finds_on_date
|
71
|
-
rescue
|
72
|
-
finds[wday] = finds_on_date
|
73
|
-
end
|
65
|
+
finds[wday] += finds_on_date
|
74
66
|
}
|
75
67
|
|
76
68
|
finds
|
@@ -78,19 +70,15 @@ module GCStats
|
|
78
70
|
|
79
71
|
def finds_by_year
|
80
72
|
@finds_by_year ||= begin
|
81
|
-
finds =
|
73
|
+
finds = Hash.new(0)
|
82
74
|
|
83
75
|
finds_by_date.each {|date, finds_on_date|
|
84
|
-
|
85
|
-
finds[date.year] += finds_on_date
|
86
|
-
rescue
|
87
|
-
finds[date.year] = finds_on_date
|
88
|
-
end
|
76
|
+
finds[date.year] += finds_on_date
|
89
77
|
}
|
90
78
|
|
91
|
-
# fill empty years with 0
|
79
|
+
# fill empty inner years with 0
|
92
80
|
(finds.keys.min + 1...finds.keys.max).each {|year|
|
93
|
-
finds[year]
|
81
|
+
finds[year] = [0, finds[year]].max
|
94
82
|
}
|
95
83
|
|
96
84
|
finds
|
@@ -98,31 +86,23 @@ module GCStats
|
|
98
86
|
end
|
99
87
|
|
100
88
|
def finds_by_size
|
101
|
-
finds =
|
89
|
+
finds = Hash.new(0)
|
102
90
|
|
103
91
|
@caches.each {|cache|
|
104
|
-
|
105
|
-
finds[cache.container] += cache.find_dates.size
|
106
|
-
rescue
|
107
|
-
finds[cache.container] = cache.find_dates.size
|
108
|
-
end
|
92
|
+
finds[cache.container] += cache.find_dates.size
|
109
93
|
}
|
110
94
|
|
111
|
-
finds.
|
95
|
+
finds.sort {|a, b| b[1] <=> a[1] }
|
112
96
|
end
|
113
97
|
|
114
98
|
def finds_by_type
|
115
|
-
finds =
|
99
|
+
finds = Hash.new(0)
|
116
100
|
|
117
101
|
@caches.each {|cache|
|
118
|
-
|
119
|
-
finds[cache.type] += cache.find_dates.size
|
120
|
-
rescue
|
121
|
-
finds[cache.type] = cache.find_dates.size
|
122
|
-
end
|
102
|
+
finds[cache.type] += cache.find_dates.size
|
123
103
|
}
|
124
104
|
|
125
|
-
finds.
|
105
|
+
finds.sort {|a, b| b[1] <=> a[1] }
|
126
106
|
end
|
127
107
|
|
128
108
|
def difficulty_terrain_combinations
|
@@ -162,14 +142,10 @@ module GCStats
|
|
162
142
|
|
163
143
|
def finds_by_country
|
164
144
|
@finds_by_country ||= begin
|
165
|
-
finds =
|
145
|
+
finds = Hash.new(0)
|
166
146
|
|
167
147
|
@caches.each {|cache|
|
168
|
-
|
169
|
-
finds[cache.country] += cache.find_dates.size
|
170
|
-
rescue
|
171
|
-
finds[cache.country] = cache.find_dates.size
|
172
|
-
end
|
148
|
+
finds[cache.country] += cache.find_dates.size
|
173
149
|
}
|
174
150
|
|
175
151
|
finds
|
@@ -194,22 +170,26 @@ module GCStats
|
|
194
170
|
|
195
171
|
def finds_by_owner
|
196
172
|
@finds_by_owner ||= begin
|
197
|
-
finds =
|
173
|
+
finds = Hash.new(0)
|
198
174
|
|
199
175
|
@caches.each {|cache|
|
200
|
-
|
201
|
-
finds[cache.owner] += cache.find_dates.size
|
202
|
-
rescue
|
203
|
-
finds[cache.owner] = cache.find_dates.size
|
204
|
-
end
|
176
|
+
finds[cache.owner] += cache.find_dates.size
|
205
177
|
}
|
206
178
|
|
207
|
-
finds.sort {|
|
179
|
+
finds.sort {|a, b| b[1] <=> a[1] }[0..9]
|
208
180
|
end
|
209
181
|
end
|
210
182
|
|
183
|
+
def oldest_cache_found
|
184
|
+
@oldest_cache_found ||= @caches.sort {|a, b| a.published <=> b.published }.first
|
185
|
+
end
|
186
|
+
|
187
|
+
def newest_cache_found
|
188
|
+
@newest_cache_found ||= @caches.sort {|a, b| a.published <=> b.published }.last
|
189
|
+
end
|
190
|
+
|
211
191
|
def geocacher_name
|
212
|
-
@caches
|
192
|
+
@caches.first.logs.first.finder
|
213
193
|
end
|
214
194
|
|
215
195
|
def finds_dates
|
@@ -217,7 +197,11 @@ module GCStats
|
|
217
197
|
end
|
218
198
|
|
219
199
|
def render_time
|
220
|
-
Time.
|
200
|
+
Time.now - @start_ts
|
201
|
+
end
|
202
|
+
|
203
|
+
def format_percent(value, total, precision = 1)
|
204
|
+
'%.*f%%' % [precision, value / total.to_f * 100]
|
221
205
|
end
|
222
206
|
end
|
223
207
|
end
|
data/lib/gcstats/server.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
-
require 'gcstats/
|
1
|
+
require 'gcstats/caches'
|
2
2
|
require 'gcstats/template'
|
3
|
-
require 'rubygems'
|
4
3
|
require 'zip/zip'
|
5
4
|
require 'sinatra'
|
6
5
|
|
7
|
-
|
8
|
-
|
6
|
+
module GCStats
|
7
|
+
module Server
|
8
|
+
get '/' do
|
9
|
+
%{\
|
9
10
|
<html>
|
10
11
|
<head>
|
11
12
|
<title>gcstats</title>
|
@@ -23,43 +24,45 @@ get '/' do
|
|
23
24
|
alt="Fork me on GitHub" /></a>
|
24
25
|
</body>
|
25
26
|
</html>
|
26
|
-
}
|
27
|
-
end
|
27
|
+
}
|
28
|
+
end
|
28
29
|
|
29
|
-
post '/generate_stats' do
|
30
|
-
|
31
|
-
|
30
|
+
post '/generate_stats' do
|
31
|
+
begin
|
32
|
+
start_ts = Time.new # for render_time helper
|
32
33
|
|
33
|
-
|
34
|
+
pq = params['pq']
|
34
35
|
|
35
|
-
|
36
|
-
|
36
|
+
if pq[:type] == 'application/zip'
|
37
|
+
data = nil
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
Zip::ZipFile.foreach(pq[:tempfile].path) {|entry|
|
40
|
+
if File.extname(entry.name) == '.gpx'
|
41
|
+
data = entry.get_input_stream.read
|
42
|
+
break
|
43
|
+
end
|
44
|
+
}
|
45
|
+
else
|
46
|
+
data = pq[:tempfile].read
|
42
47
|
end
|
43
|
-
}
|
44
|
-
else
|
45
|
-
data = pq[:tempfile].read
|
46
|
-
end
|
47
48
|
|
48
|
-
|
49
|
+
datadir = File.join(File.dirname(__FILE__), '..', '..', 'data', 'gcstats')
|
49
50
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
51
|
+
rhtml = open(File.join(datadir, 'gcstats.rhtml')).read
|
52
|
+
caches = GCStats::Caches.from_xml(data)
|
53
|
+
data = {:caches => caches, :start_ts => start_ts}
|
54
|
+
html = GCStats::Template.new(rhtml, data).result
|
55
|
+
html.sub!('/* %css% */', "\n" + File.read(File.join(datadir, 'gcstats.css')))
|
56
|
+
html.sub!('/* %js% */', "\n" + File.read(File.join(datadir, 'gcstats.js')))
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
58
|
+
return html
|
59
|
+
rescue
|
60
|
+
halt 500, '<h1>Internal Server Error</h1>'
|
61
|
+
end
|
62
|
+
end
|
62
63
|
|
63
|
-
not_found do
|
64
|
-
|
64
|
+
not_found do
|
65
|
+
'<h1>Not Found</h1>'
|
66
|
+
end
|
67
|
+
end
|
65
68
|
end
|
data/lib/gcstats/version.rb
CHANGED