gcstats 1.0.0 → 1.0.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.
@@ -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