gcstats 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -18,15 +18,17 @@ To install, change directory to where you have extracted the gcstats source file
18
18
 
19
19
  Visit the [Pocket Queries][pq] page and click the _Add to Queue_ button (under _My Finds_). After a while, you will receive an email informing you that your Pocket Query file is available for download. Visit the [Pocket Queries][pq] page again and download the file under the _Pocket Queries Ready for Download_ tab.
20
20
 
21
- Assuming your Pocket Query file is _3627915.zip_, issue:
21
+ Assuming your Pocket Query file is _1234567.zip_, issue:
22
22
 
23
- ruby gcstats.rb 3627915.zip
23
+ gcstats 1234567.zip
24
24
 
25
- Open _3627915.html_ to view your statistics. It is also possible to specify the output filename:
25
+ This will write to _username.html_, where "username" is the one you have on [Geocaching.com][gc].
26
26
 
27
- ruby gcstats.rb 3627915.zip agorf.html
27
+ It is also possible to specify the output filename:
28
28
 
29
- Will write to _agorf.html_.
29
+ gcstats 1234567.zip mystats.html
30
+
31
+ This will write to _mystats.html_.
30
32
 
31
33
  **Note:** You need to be a [Premium Member][pm] at [Geocaching.com][gc] to use [Pocket Queries][pq].
32
34
 
data/bin/gcstats CHANGED
@@ -12,6 +12,8 @@ if in_fn.nil?
12
12
  exit 1
13
13
  end
14
14
 
15
+ start_ts = Time.new # for render_time helper
16
+
15
17
  if File.extname(in_fn) == '.zip'
16
18
  data = nil
17
19
 
@@ -27,12 +29,22 @@ else
27
29
  out_fn ||= File.basename(in_fn, File.extname(in_fn)) + '.html'
28
30
  end
29
31
 
30
- lib_dir = File.join(File.dirname(__FILE__), '..', 'lib', 'gcstats')
32
+ libdir = File.join(File.dirname(__FILE__), '..', 'lib', 'gcstats')
31
33
 
32
- rhtml = File.read(File.join(lib_dir, 'gcstats.rhtml'))
34
+ rhtml = File.read(File.join(libdir, 'gcstats.rhtml'))
33
35
  caches = GCStats::Caches.from_xml(data)
34
- html = GCStats::Template.new(rhtml, :caches => caches).result
35
- html.sub!('/* %css% */', "\n" + File.read(File.join(lib_dir, 'gcstats.css')))
36
- html.sub!('/* %js% */', "\n" + File.read(File.join(lib_dir, 'gcstats.js')))
36
+ data = {:caches => caches, :start_ts => start_ts}
37
+ html = GCStats::Template.new(rhtml, data).result
38
+ html.sub!('/* %css% */', "\n" + File.read(File.join(libdir, 'gcstats.css')))
39
+ html.sub!('/* %js% */', "\n" + File.read(File.join(libdir, 'gcstats.js')))
40
+
41
+ if ARGV[1].nil? && caches[0] && caches[0].logs[0]
42
+ out_fn = caches[0].logs[0].finder
43
+ out_fn.downcase!
44
+ out_fn.gsub!(/\W/, '-')
45
+ out_fn.gsub!(/-+/, '-')
46
+ out_fn += '.html'
47
+ end
48
+
37
49
  open(out_fn, 'w') {|f| f.write(html) }
38
- puts "wrote #{out_fn}" if test(?s, out_fn)
50
+ puts "wrote #{out_fn}" if test(?s, out_fn)
data/config.ru CHANGED
@@ -1,3 +1,6 @@
1
+ libdir = File.join(File.dirname(__FILE__), 'lib')
2
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
+
1
4
  require 'gcstats/server'
2
5
 
3
6
  run Sinatra::Application
@@ -2,7 +2,7 @@
2
2
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
3
  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
4
4
  <head>
5
- <title><%= geocacher_name %>'s Geocaching Stats</title>
5
+ <title>Geocaching Stats for <%=h geocacher_name %></title>
6
6
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
7
7
  <link type="text/css" rel="stylesheet" href="gcstats.css" media="screen" />
8
8
  <style type="text/css">/* %css% */</style>
@@ -17,7 +17,7 @@
17
17
  <caption>Cache Finds</caption>
18
18
  <tr>
19
19
  <th class="l">Geocacher</th>
20
- <td class="hl b"><%= geocacher_name %></td>
20
+ <td class="hl b"><%=h geocacher_name %></td>
21
21
  </tr>
22
22
  <tr>
23
23
  <th class="l">Total</th>
@@ -88,7 +88,7 @@
88
88
  </tr>
89
89
  <% finds_by_size.each {|size, finds| %>
90
90
  <tr>
91
- <td><%= size %></td>
91
+ <td><%=h size %></td>
92
92
  <td class="r"><%= finds %></td>
93
93
  <td class="r"><%= '%.1f' % (finds / total_finds.to_f * 100) %>%</td>
94
94
  </tr>
@@ -106,7 +106,25 @@
106
106
  </tr>
107
107
  <% finds_by_type.each {|type, finds| %>
108
108
  <tr>
109
- <td><%= type %></td>
109
+ <td><%=h type %></td>
110
+ <td class="r"><%= finds %></td>
111
+ <td class="r"><%= '%.1f' % (finds / total_finds.to_f * 100) %>%</td>
112
+ </tr>
113
+ <% } %>
114
+ </table>
115
+ <%# }}} %>
116
+
117
+ <%# {{{ finds by cache owner %>
118
+ <table>
119
+ <caption>Finds by Cache Owner</caption>
120
+ <tr>
121
+ <th>Owner</th>
122
+ <th>Finds</th>
123
+ <th>Percentage</th>
124
+ </tr>
125
+ <% finds_by_owner.each {|owner, finds| %>
126
+ <tr>
127
+ <td><%=h owner %></td>
110
128
  <td class="r"><%= finds %></td>
111
129
  <td class="r"><%= '%.1f' % (finds / total_finds.to_f * 100) %>%</td>
112
130
  </tr>
@@ -182,7 +200,7 @@
182
200
  </tr>
183
201
  <% finds_by_country.sort {|x, y| y[1] <=> x[1] }.each {|country, finds| %>
184
202
  <tr>
185
- <td><%= country %></td>
203
+ <td><%=h country %></td>
186
204
  <td class="r"><%= finds %></td>
187
205
  <td class="r"><%= '%.1f' % (finds / total_finds.to_f * 100) %>%</td>
188
206
  </tr>
@@ -190,6 +208,32 @@
190
208
  </table>
191
209
  <%# }}} %>
192
210
 
211
+ <%# {{{ finds by state %>
212
+ <% finds_by_state.each {|country, states| %>
213
+ <table>
214
+ <caption>Finds by State in <%=h country %></caption>
215
+ <tr>
216
+ <th rowspan="2">State</th>
217
+ <th rowspan="2">Finds</th>
218
+ <th colspan="2">Percentage</th>
219
+ </tr>
220
+ <tr>
221
+ <th>Country</th>
222
+ <th>Total</th>
223
+ </tr>
224
+ <% country_finds = states.map {|s| s[1] }.sum %>
225
+ <% states.sort {|x, y| y[1] <=> x[1] }.each {|state, finds| %>
226
+ <tr>
227
+ <td><%=h state %></td>
228
+ <td class="r"><%= finds %></td>
229
+ <td class="r"><%= '%.1f' % (finds / country_finds.to_f * 100) %>%</td>
230
+ <td class="r"><%= '%.1f' % (finds / total_finds.to_f * 100) %>%</td>
231
+ </tr>
232
+ <% } %>
233
+ </table>
234
+ <% } %>
235
+ <%# }}} %>
236
+
193
237
  <%# {{{ finds by date %>
194
238
  <table id="finds_by_date">
195
239
  <caption>Finds by Date</caption>
@@ -209,5 +253,7 @@
209
253
  </table>
210
254
  <%# }}} %>
211
255
 
256
+ <p>Generated with <a href="http://github.com/agorf/gcstats">gcstats</a> on <%= Time.new %> in <%= '%.3f' % render_time %> seconds.</p>
257
+
212
258
  </body>
213
259
  </html>
@@ -176,6 +176,38 @@ module GCStats
176
176
  end
177
177
  end
178
178
 
179
+ def finds_by_state
180
+ @finds_by_state ||= begin
181
+ finds = {}
182
+
183
+ @caches.each {|cache|
184
+ next if cache.state.empty?
185
+
186
+ finds[cache.country] ||= {}
187
+ finds[cache.country][cache.state] ||= 0
188
+ finds[cache.country][cache.state] += cache.find_dates.size
189
+ }
190
+
191
+ finds
192
+ end
193
+ end
194
+
195
+ def finds_by_owner
196
+ @finds_by_owner ||= begin
197
+ finds = {}
198
+
199
+ @caches.each {|cache|
200
+ begin
201
+ finds[cache.owner] += cache.find_dates.size
202
+ rescue
203
+ finds[cache.owner] = cache.find_dates.size
204
+ end
205
+ }
206
+
207
+ finds.sort {|x, y| y[1] <=> x[1] }[0..9]
208
+ end
209
+ end
210
+
179
211
  def geocacher_name
180
212
  @caches[0].logs[0].finder
181
213
  end
@@ -183,5 +215,9 @@ module GCStats
183
215
  def finds_dates
184
216
  @finds_dates ||= finds_by_date.keys.sort.reverse
185
217
  end
218
+
219
+ def render_time
220
+ Time.new - @start_ts
221
+ end
186
222
  end
187
223
  end
@@ -60,10 +60,12 @@ module GCStats
60
60
  end
61
61
 
62
62
  def owner
63
- @owner ||= @cache_node.elements["#{NS}:placed_by"].text
63
+ @owner ||= @cache_node.elements["#{NS}:owner"].text
64
64
  end
65
65
 
66
- alias :placed_by :owner
66
+ def placed_by
67
+ @placed_by ||= @cache_node.elements["#{NS}:placed_by"].text
68
+ end
67
69
 
68
70
  def type
69
71
  @type ||= @cache_node.elements["#{NS}:type"].text
@@ -88,7 +90,7 @@ module GCStats
88
90
  end
89
91
 
90
92
  def state
91
- @state ||= @cache_node.elements["#{NS}:state"].text
93
+ @state ||= @cache_node.elements["#{NS}:state"].text.strip
92
94
  end
93
95
 
94
96
  def logs
@@ -28,6 +28,8 @@ end
28
28
 
29
29
  post '/generate_stats' do
30
30
  begin
31
+ start_ts = Time.new # for render_time helper
32
+
31
33
  pq = params['pq']
32
34
 
33
35
  if pq[:type] == 'application/zip'
@@ -43,13 +45,14 @@ post '/generate_stats' do
43
45
  data = pq[:tempfile].read
44
46
  end
45
47
 
46
- lib_dir = File.dirname(__FILE__)
48
+ libdir = File.dirname(__FILE__)
47
49
 
48
- rhtml = open(File.join(lib_dir, 'gcstats.rhtml')).read
50
+ rhtml = open(File.join(libdir, 'gcstats.rhtml')).read
49
51
  caches = GCStats::Caches.from_xml(data)
50
- html = GCStats::Template.new(rhtml, :caches => caches).result
51
- html.sub!('/* %css% */', "\n" + File.read(File.join(lib_dir, 'gcstats.css')))
52
- html.sub!('/* %js% */', "\n" + File.read(File.join(lib_dir, 'gcstats.js')))
52
+ data = {:caches => caches, :start_ts => start_ts}
53
+ html = GCStats::Template.new(rhtml, data).result
54
+ html.sub!('/* %css% */', "\n" + File.read(File.join(libdir, 'gcstats.css')))
55
+ html.sub!('/* %js% */', "\n" + File.read(File.join(libdir, 'gcstats.js')))
53
56
 
54
57
  return html
55
58
  rescue
@@ -14,6 +14,10 @@ module GCStats
14
14
  ERB.new(@text).result(binding)
15
15
  end
16
16
 
17
+ def h(s)
18
+ ERB::Util.html_escape(s)
19
+ end
20
+
17
21
  alias :to_s :result
18
22
  end
19
23
  end
@@ -0,0 +1,3 @@
1
+ module GCStats
2
+ VERSION = '1.0.1'
3
+ end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gcstats
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ hash: 21
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 1
10
+ version: 1.0.1
5
11
  platform: ruby
6
12
  authors:
7
13
  - Aggelos Orfanakos
@@ -9,19 +15,23 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-08-30 00:00:00 +03:00
18
+ date: 2010-09-20 00:00:00 +03:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
22
  name: rubyzip
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
20
26
  requirements:
21
27
  - - ">="
22
28
  - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
23
32
  version: "0"
24
- version:
33
+ type: :runtime
34
+ version_requirements: *id001
25
35
  description: Simple and clean statistics of your Geocaching activity
26
36
  email: agorf@agorf.gr
27
37
  executables:
@@ -31,9 +41,10 @@ extensions: []
31
41
  extra_rdoc_files: []
32
42
 
33
43
  files:
34
- - README.markdown
44
+ - README.md
35
45
  - config.ru
36
46
  - bin/gcstats
47
+ - lib/gcstats/version.rb
37
48
  - lib/gcstats/gcstats.css
38
49
  - lib/gcstats/helpers.rb
39
50
  - lib/gcstats/mapping.rb
@@ -51,21 +62,27 @@ rdoc_options: []
51
62
  require_paths:
52
63
  - lib
53
64
  required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
54
66
  requirements:
55
67
  - - ">="
56
68
  - !ruby/object:Gem::Version
69
+ hash: 3
70
+ segments:
71
+ - 0
57
72
  version: "0"
58
- version:
59
73
  required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
60
75
  requirements:
61
76
  - - ">="
62
77
  - !ruby/object:Gem::Version
78
+ hash: 3
79
+ segments:
80
+ - 0
63
81
  version: "0"
64
- version:
65
82
  requirements: []
66
83
 
67
84
  rubyforge_project:
68
- rubygems_version: 1.3.5
85
+ rubygems_version: 1.3.7
69
86
  signing_key:
70
87
  specification_version: 3
71
88
  summary: Simple and clean statistics of your Geocaching activity