gcstats 1.0.1 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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