ghaki-stats 2011.11.29.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.
- data/LICENSE +19 -0
- data/README +23 -0
- data/VERSION +1 -0
- data/lib/ghaki/stats/app.rb +14 -0
- data/lib/ghaki/stats/base.rb +216 -0
- data/lib/ghaki/stats/errors.rb +27 -0
- data/lib/ghaki/stats/format/base.rb +39 -0
- data/lib/ghaki/stats/format/logger.rb +33 -0
- data/lib/ghaki/stats/format/null.rb +12 -0
- data/lib/ghaki/stats/format/output.rb +24 -0
- data/lib/ghaki/stats/mixin.rb +27 -0
- data/lib/ghaki/stats/spec_helper.rb +26 -0
- data/spec/ghaki/stats/app_engine_spec.rb +36 -0
- data/spec/ghaki/stats/app_stats_spec.rb +45 -0
- data/spec/ghaki/stats/base_spec.rb +302 -0
- data/spec/ghaki/stats/format/base_spec.rb +44 -0
- data/spec/ghaki/stats/format/logger_spec.rb +54 -0
- data/spec/ghaki/stats/format/null_spec.rb +15 -0
- data/spec/ghaki/stats/format/output_spec.rb +37 -0
- data/spec/ghaki/stats/mixin_spec.rb +25 -0
- data/spec/ghaki/stats/spec_helper_spec.rb +41 -0
- data/spec/spec_helper.rb +6 -0
- metadata +132 -0
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010 Gerald Kalafut
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
= Ghaki Stats - Simple statistics.
|
2
|
+
|
3
|
+
Ghaki Stats is simple tracker for counted statistics.
|
4
|
+
|
5
|
+
== Download
|
6
|
+
|
7
|
+
The latest version of Ghaki Stats can be found at
|
8
|
+
|
9
|
+
* git@github.com:ghaki/ghaki-stats.git
|
10
|
+
|
11
|
+
== Installation
|
12
|
+
|
13
|
+
The preferred method of installing Ghaki Stats is through its GEM file.
|
14
|
+
|
15
|
+
% [sudo] gem install ghaki-stats-1.0.0.gem
|
16
|
+
|
17
|
+
== License
|
18
|
+
|
19
|
+
Ghaki Stats is released under the MIT license.
|
20
|
+
|
21
|
+
== Support
|
22
|
+
|
23
|
+
Contact mailto:gerald@kalafut.org
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2011.11.29.1
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'ghaki/app/plugin'
|
2
|
+
require 'ghaki/stats/base'
|
3
|
+
|
4
|
+
module Ghaki #:nodoc:
|
5
|
+
module Stats #:nodoc:
|
6
|
+
|
7
|
+
# Application wide statistics tracker.
|
8
|
+
|
9
|
+
class App < Ghaki::App::Plugin
|
10
|
+
app_plugin_make Base, :stats
|
11
|
+
app_plugin_link :stats
|
12
|
+
end
|
13
|
+
|
14
|
+
end end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'ghaki/stats/errors'
|
2
|
+
require 'ghaki/stats/format/logger'
|
3
|
+
|
4
|
+
############################################################################
|
5
|
+
module Ghaki #:nodoc
|
6
|
+
module Stats #:nodoc
|
7
|
+
|
8
|
+
class Base
|
9
|
+
|
10
|
+
attr_accessor :title # Title of statistics output report.
|
11
|
+
attr_writer :format # Statistics output report Formatting object.
|
12
|
+
|
13
|
+
=begin
|
14
|
+
[+format+] Statistics report formatting object.
|
15
|
+
[+title+] Title of statistics output report.
|
16
|
+
=end
|
17
|
+
|
18
|
+
def initialize opts={}
|
19
|
+
clear
|
20
|
+
@format = opts[:format]
|
21
|
+
@title = opts[:title] || ''
|
22
|
+
end
|
23
|
+
|
24
|
+
# Get the formatter for the statistical report.
|
25
|
+
#
|
26
|
+
# Note: Will generate default formatting object if not already set.
|
27
|
+
|
28
|
+
def format
|
29
|
+
@format ||= self._format_default
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
# Assign zeroe to a stats count if its not already set.
|
34
|
+
|
35
|
+
def def_zero major, minor
|
36
|
+
def_value major, minor, 0
|
37
|
+
end
|
38
|
+
|
39
|
+
# Assign zeroes to multiple stats counts if they're not already set.
|
40
|
+
|
41
|
+
def def_zeros major_to_minor
|
42
|
+
major_to_minor.each_pair do |major,minor_s|
|
43
|
+
[*minor_s].each do |minor|
|
44
|
+
def_zero major, minor
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Assign multiple stats counts if not already set.
|
50
|
+
|
51
|
+
def def_values major, value, *minors
|
52
|
+
minors.each { |minor| def_value major, minor, value }
|
53
|
+
end
|
54
|
+
|
55
|
+
# Assign default stats count value if not already set.
|
56
|
+
|
57
|
+
def def_value major, minor, value
|
58
|
+
@stats[major] ||= {}
|
59
|
+
@stats[major][minor] = value unless @stats[major].has_key?(minor)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Increase stats count by 1.
|
63
|
+
|
64
|
+
def incr major, minor
|
65
|
+
incr_by major, minor, 1
|
66
|
+
end
|
67
|
+
|
68
|
+
# Decrease stats count by 1.
|
69
|
+
|
70
|
+
def decr major, minor
|
71
|
+
decr_by major, minor, 1
|
72
|
+
end
|
73
|
+
|
74
|
+
# Increase stats count by a given value.
|
75
|
+
|
76
|
+
def incr_by major, minor, value
|
77
|
+
def_zero major, minor
|
78
|
+
@stats[major][minor] += value
|
79
|
+
end
|
80
|
+
|
81
|
+
# Decrease stats count by a given value
|
82
|
+
|
83
|
+
def decr_by major, minor, value
|
84
|
+
def_zero major, minor
|
85
|
+
@stats[major][minor] -= value
|
86
|
+
end
|
87
|
+
|
88
|
+
# Set stats count to a given value.
|
89
|
+
|
90
|
+
def put major, minor, value
|
91
|
+
@stats[major] ||= {}
|
92
|
+
@stats[major][minor] = value
|
93
|
+
end
|
94
|
+
|
95
|
+
# Is stat present?
|
96
|
+
|
97
|
+
def has? major, minor=nil
|
98
|
+
if @stats.has_key?(major)
|
99
|
+
if minor.nil?
|
100
|
+
true
|
101
|
+
else
|
102
|
+
@stats[major].has_key?(minor)
|
103
|
+
end
|
104
|
+
else
|
105
|
+
false
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Is stat missing?
|
110
|
+
|
111
|
+
def lacks? major, minor=nil
|
112
|
+
! has?(major,minor)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Throw exception if stat is mising.
|
116
|
+
|
117
|
+
def has! major, minor=nil
|
118
|
+
return self if has? major, minor
|
119
|
+
if minor.nil?
|
120
|
+
raise MissingMajorStatsError.new(major)
|
121
|
+
else
|
122
|
+
raise MissingMinorStatsError.new(major, minor)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Get current value of stats count. Defaults to zero when not present.
|
127
|
+
|
128
|
+
def get major, minor
|
129
|
+
return 0 unless @stats.has_key?(major)
|
130
|
+
return 0 unless @stats[major].has_key?(minor)
|
131
|
+
return @stats[major][minor]
|
132
|
+
end
|
133
|
+
|
134
|
+
# Get current value or throw exception.
|
135
|
+
|
136
|
+
def get! major, minor
|
137
|
+
has!(major,minor).get(major,minor)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Get current value of stats count. Defaults to specified when not present.
|
141
|
+
|
142
|
+
def get? major, minor, defval=nil
|
143
|
+
if has? major, minor
|
144
|
+
get major, minor
|
145
|
+
else
|
146
|
+
defval
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Set stats value if given value is greater than current value.
|
151
|
+
|
152
|
+
def set_gt major, minor, value
|
153
|
+
if not @stats.has_key?(major)
|
154
|
+
@stats[major] = { minor => value }
|
155
|
+
elsif not @stats[major].has_key?(minor)
|
156
|
+
@stats[major][minor] = value
|
157
|
+
elsif @stats[major][minor] < value
|
158
|
+
@stats[major][minor] = value
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Set stats value if given value is less than current value.
|
163
|
+
|
164
|
+
def set_lt major, minor, value
|
165
|
+
if not @stats.has_key?(major)
|
166
|
+
@stats[major] = { minor => value }
|
167
|
+
elsif not @stats[major].has_key?(minor)
|
168
|
+
@stats[major][minor] = value
|
169
|
+
elsif @stats[major][minor] > value
|
170
|
+
@stats[major][minor] = value
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Clears statistic counts.
|
175
|
+
|
176
|
+
def clear
|
177
|
+
@stats = {}
|
178
|
+
end
|
179
|
+
|
180
|
+
# Writes statistics report to specified output file.
|
181
|
+
|
182
|
+
def dump out_file, title=@title
|
183
|
+
format.dump @stats, out_file, title
|
184
|
+
end
|
185
|
+
|
186
|
+
# Logger specific dump. (DEPRECATED)
|
187
|
+
|
188
|
+
def log_dump logger, title=@title
|
189
|
+
warn "[DEPRECATED] 'log_dump' is deprecated. Please use 'dump' instead."
|
190
|
+
dump logger, title
|
191
|
+
end
|
192
|
+
|
193
|
+
# Writes statistics report to specified output file, and clears statistic counts.
|
194
|
+
def flush out_file, title=@title
|
195
|
+
dump out_file, title
|
196
|
+
ensure
|
197
|
+
clear
|
198
|
+
end
|
199
|
+
|
200
|
+
# Logger specific flush. (DEPRECATED)
|
201
|
+
|
202
|
+
def log_flush logger, title=@title
|
203
|
+
warn "[DEPRECATED] 'log_flush' is deprecated. Please use 'flush' instead."
|
204
|
+
flush logger, title
|
205
|
+
end
|
206
|
+
|
207
|
+
protected
|
208
|
+
|
209
|
+
def _format_default #:nodoc
|
210
|
+
opts = {}
|
211
|
+
opts[:title] = @title unless @title.nil?
|
212
|
+
Ghaki::Stats::Format::Logger.new( opts )
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
end end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'ghaki/stats/errors'
|
2
|
+
|
3
|
+
module Ghaki #:nodoc:
|
4
|
+
|
5
|
+
class MissingMajorStatsError < RuntimeError
|
6
|
+
attr_accessor :major
|
7
|
+
def blurb
|
8
|
+
" Major (#{@major})"
|
9
|
+
end
|
10
|
+
def initialize maj, msg='Missing Statistic'
|
11
|
+
@major = maj
|
12
|
+
super( msg + ':' + blurb() )
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class MissingMinorStatsError < MissingMajorStatsError
|
17
|
+
attr_accessor :minor
|
18
|
+
def blurb
|
19
|
+
super() + " Minor (#{@minor})"
|
20
|
+
end
|
21
|
+
def initialize maj, min, msg='Missing Statistic'
|
22
|
+
@minor = min
|
23
|
+
super( maj, msg )
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
############################################################################
|
2
|
+
module Ghaki #:nodoc:
|
3
|
+
module Stats #:nodoc:
|
4
|
+
module Format #:nodoc:
|
5
|
+
|
6
|
+
# Base for Statistics Report formatting objects.
|
7
|
+
|
8
|
+
class Base
|
9
|
+
|
10
|
+
attr_accessor :title # Name of statistics report.
|
11
|
+
|
12
|
+
def initialize opts={}
|
13
|
+
@title = opts[:title] || ''
|
14
|
+
end
|
15
|
+
|
16
|
+
# Dump output from statistics object.
|
17
|
+
|
18
|
+
def dump stats, out, title=@title
|
19
|
+
dump_head stats, out, title
|
20
|
+
dump_body stats, out, title
|
21
|
+
dump_tail stats, out, title
|
22
|
+
end
|
23
|
+
|
24
|
+
# Generate header of report.
|
25
|
+
|
26
|
+
def dump_head stats, out, title
|
27
|
+
end
|
28
|
+
|
29
|
+
# Generate body of report.
|
30
|
+
def dump_body stats, out, title
|
31
|
+
end
|
32
|
+
|
33
|
+
# Generate footer of report.
|
34
|
+
|
35
|
+
def dump_tail stats, out, title
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end end end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'ghaki/stats/format/output'
|
2
|
+
|
3
|
+
############################################################################
|
4
|
+
module Ghaki #:nodoc:
|
5
|
+
module Stats #:nodoc:
|
6
|
+
module Format #:nodoc:
|
7
|
+
|
8
|
+
# Default formatting for generating Statistics Reports using a Logger object.
|
9
|
+
|
10
|
+
class Logger < Output
|
11
|
+
|
12
|
+
# Dump heading info, which in this case is a minor began log.
|
13
|
+
|
14
|
+
def dump_head stats, log, title
|
15
|
+
if title.empty?
|
16
|
+
log.minor.began 'dumping statistics'
|
17
|
+
else
|
18
|
+
log.box title
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Dump footer info, which in this case is a minor ended log.
|
23
|
+
|
24
|
+
def dump_tail stats, log, title
|
25
|
+
if title.empty?
|
26
|
+
log.minor.ended 'dumping statistics'
|
27
|
+
else
|
28
|
+
log.liner
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end # class
|
33
|
+
end end end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'ghaki/stats/format/base'
|
2
|
+
|
3
|
+
module Ghaki #:nodoc:
|
4
|
+
module Stats #:nodoc:
|
5
|
+
module Format #:nodoc:
|
6
|
+
|
7
|
+
# Default formatting for generating Statistics Reports using an output file object.
|
8
|
+
|
9
|
+
class Output < Base
|
10
|
+
|
11
|
+
# Dumps body of stats.
|
12
|
+
|
13
|
+
def dump_body stats, log, title
|
14
|
+
stats.keys.sort.each do |major|
|
15
|
+
log.puts major + ':'
|
16
|
+
stats[major].keys.sort.each do |minor|
|
17
|
+
count = stats[major][minor]
|
18
|
+
log.puts ' ' + count.to_s.rjust(8) + ' : ' + minor
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end # class
|
24
|
+
end end end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'ghaki/app/mixable'
|
2
|
+
require 'ghaki/stats/base'
|
3
|
+
|
4
|
+
module Ghaki #:nodoc
|
5
|
+
module Stats #:nodoc
|
6
|
+
|
7
|
+
# Mixin stats object with auto-first use object creation.
|
8
|
+
#
|
9
|
+
# Note: Creates new Base stats object, does not grab copy from App Engine.
|
10
|
+
# ==== Example
|
11
|
+
#
|
12
|
+
# class MyAction
|
13
|
+
# include Ghaki::Stats::Mixin
|
14
|
+
# def do_something
|
15
|
+
# stats.incr 'Did', 'Something'
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# myact = MyAction.new
|
20
|
+
# myact.do_something
|
21
|
+
|
22
|
+
module Mixin
|
23
|
+
include Ghaki::App::Mixable
|
24
|
+
app_mixin_accessor Base, :stats
|
25
|
+
end
|
26
|
+
|
27
|
+
end end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'ghaki/stats/base'
|
2
|
+
require 'ghaki/stats/format/null'
|
3
|
+
|
4
|
+
module Ghaki #:nodoc:
|
5
|
+
module Stats #:nodoc:
|
6
|
+
|
7
|
+
# Helper for mocking Ghaki::Stats objects in unit tests.
|
8
|
+
module SpecHelper
|
9
|
+
|
10
|
+
DEF_CLASS=Ghaki::Stats::Base
|
11
|
+
|
12
|
+
# Creates Ghaki::Stats object:
|
13
|
+
# - Using null sink formatting to avoid file access.
|
14
|
+
def make_safe_stats klass=DEF_CLASS
|
15
|
+
obj = klass.new
|
16
|
+
obj.format = Ghaki::Stats::Format::Null.new
|
17
|
+
obj
|
18
|
+
end
|
19
|
+
|
20
|
+
# Creates @stats member using :make_safe_stats
|
21
|
+
def setup_safe_stats klass=DEF_CLASS
|
22
|
+
@stats = make_safe_stats(klass)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'ghaki/stats/app'
|
2
|
+
|
3
|
+
describe Ghaki::App::Engine do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
@app_eng = Ghaki::App::Engine.instance
|
7
|
+
@sta_app = Ghaki::Stats::App.instance
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'singleton' do
|
11
|
+
subject { @app_eng }
|
12
|
+
it { should respond_to :stats }
|
13
|
+
it { should respond_to :stats= }
|
14
|
+
it { should respond_to :stats_opts }
|
15
|
+
it { should respond_to :stats_opts= }
|
16
|
+
it { should respond_to :stats_defs }
|
17
|
+
it { should respond_to :stats_defs= }
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#stats' do
|
21
|
+
subject { @app_eng.stats }
|
22
|
+
specify { should be_an_instance_of(Ghaki::Stats::Base) }
|
23
|
+
specify { should equal(@sta_app.stats ) }
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#stats_opts' do
|
27
|
+
subject { @app_eng.stats_opts }
|
28
|
+
specify { should be_an_instance_of(::Hash) }
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#stats_defs' do
|
32
|
+
subject { @app_eng.stats_defs }
|
33
|
+
specify { should be_an_instance_of(::Hash) }
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
############################################################################
|
2
|
+
require 'ghaki/stats/app'
|
3
|
+
|
4
|
+
############################################################################
|
5
|
+
module Ghaki module Stats module AppTesting
|
6
|
+
describe Ghaki::Stats::App do
|
7
|
+
|
8
|
+
########################################################################
|
9
|
+
context 'singleton' do
|
10
|
+
subject { Ghaki::Stats::App.instance }
|
11
|
+
it { should respond_to :stats }
|
12
|
+
it { should respond_to :stats= }
|
13
|
+
it { should respond_to :stats_opts }
|
14
|
+
it { should respond_to :stats_opts= }
|
15
|
+
end
|
16
|
+
|
17
|
+
########################################################################
|
18
|
+
context 'singleton methods' do
|
19
|
+
|
20
|
+
describe '#stats' do
|
21
|
+
subject { Ghaki::Stats::App.instance.stats }
|
22
|
+
specify { should be_an_instance_of(Ghaki::Stats::Base) }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#stats_opts' do
|
26
|
+
subject { Ghaki::Stats::App.instance.stats_opts }
|
27
|
+
specify { should be_an_instance_of(::Hash) }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'default settings' do
|
31
|
+
describe '#title' do
|
32
|
+
subject { Ghaki::Stats::App.instance.stats.title }
|
33
|
+
specify { should be_empty }
|
34
|
+
end
|
35
|
+
describe '#format' do
|
36
|
+
subject { Ghaki::Stats::App.instance.stats.format }
|
37
|
+
specify { should be_an_instance_of(Ghaki::Stats::Format::Logger) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end end end
|
45
|
+
############################################################################
|
@@ -0,0 +1,302 @@
|
|
1
|
+
require 'ghaki/stats/errors'
|
2
|
+
require 'ghaki/stats/base'
|
3
|
+
require 'ghaki/stats/spec_helper'
|
4
|
+
|
5
|
+
module Ghaki module Stats module Base_Testing
|
6
|
+
describe Ghaki::Stats::Base do
|
7
|
+
include Ghaki::Stats::SpecHelper
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
setup_safe_stats
|
11
|
+
end
|
12
|
+
|
13
|
+
subject { @stats }
|
14
|
+
|
15
|
+
it { should respond_to :title }
|
16
|
+
it { should respond_to :title= }
|
17
|
+
it { should respond_to :format= }
|
18
|
+
|
19
|
+
describe '#put' do
|
20
|
+
it 'stores value' do
|
21
|
+
subject.put 'inputs', 'wrote', 3
|
22
|
+
subject.get('inputs','wrote').should == 3
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#has?' do
|
27
|
+
context 'using major only' do
|
28
|
+
it 'detects missing' do
|
29
|
+
subject.put 'a', 'b', 3
|
30
|
+
subject.has?('c').should be_false
|
31
|
+
end
|
32
|
+
it 'detects present' do
|
33
|
+
subject.put 'a', 'b', 3
|
34
|
+
subject.has?('a').should be_true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
context 'using major and minor' do
|
38
|
+
it 'detects missing' do
|
39
|
+
subject.put 'a', 'b', 3
|
40
|
+
subject.has?('a','c').should be_false
|
41
|
+
end
|
42
|
+
it 'detects present' do
|
43
|
+
subject.put 'a', 'b', 3
|
44
|
+
subject.has?('a','b').should be_true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#lacks?' do
|
50
|
+
context 'using major only' do
|
51
|
+
it 'detects missing' do
|
52
|
+
subject.put 'a', 'b', 3
|
53
|
+
subject.lacks?('c').should be_true
|
54
|
+
end
|
55
|
+
it 'detects present' do
|
56
|
+
subject.put 'a', 'b', 3
|
57
|
+
subject.lacks?('a').should be_false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
context 'using major and minor' do
|
61
|
+
it 'detects missing' do
|
62
|
+
subject.put 'a', 'b', 3
|
63
|
+
subject.lacks?('a','c').should be_true
|
64
|
+
end
|
65
|
+
it 'detects present' do
|
66
|
+
subject.put 'a', 'b', 3
|
67
|
+
subject.lacks?('a','b').should be_false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#has!' do
|
73
|
+
context 'using major only' do
|
74
|
+
it 'fails on missing' do
|
75
|
+
subject.put 'a', 'b', 3
|
76
|
+
lambda do
|
77
|
+
subject.has!('c')
|
78
|
+
end.should raise_error(MissingMajorStatsError)
|
79
|
+
end
|
80
|
+
it 'detects present' do
|
81
|
+
subject.put 'a', 'b', 3
|
82
|
+
subject.has!('a').should == subject
|
83
|
+
end
|
84
|
+
end
|
85
|
+
context 'using major and minor' do
|
86
|
+
it 'fails on missing' do
|
87
|
+
subject.put 'a', 'b', 3
|
88
|
+
lambda do
|
89
|
+
subject.has!('a','c')
|
90
|
+
end.should raise_error(MissingMinorStatsError)
|
91
|
+
end
|
92
|
+
it 'detects present' do
|
93
|
+
subject.put 'a', 'b', 3
|
94
|
+
subject.has!('a','b').should == subject
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#get' do
|
100
|
+
it 'retrieves value when set' do
|
101
|
+
subject.put 'inputs','present',23
|
102
|
+
subject.get('inputs','present').should == 23
|
103
|
+
end
|
104
|
+
it "defaults to zero when not set" do
|
105
|
+
subject.get('inputs','bogus').should == 0
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '#get?' do
|
110
|
+
context 'when stat is present' do
|
111
|
+
it 'gets value' do
|
112
|
+
subject.put 'inputs','present',23
|
113
|
+
subject.get?('inputs','present').should == 23
|
114
|
+
end
|
115
|
+
end
|
116
|
+
context 'when stat is missing' do
|
117
|
+
it 'returns nil without specified default' do
|
118
|
+
subject.get?('inputs','bogus').should be_nil
|
119
|
+
end
|
120
|
+
it 'returns specified default' do
|
121
|
+
subject.get?('inputs','bogus',54).should == 54
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe '#get!' do
|
127
|
+
it 'fails on missing' do
|
128
|
+
subject.put 'a', 'b', 3
|
129
|
+
lambda do
|
130
|
+
subject.get!('c','b')
|
131
|
+
end.should raise_error(MissingMinorStatsError)
|
132
|
+
end
|
133
|
+
it 'detects present' do
|
134
|
+
subject.put 'a', 'b', 3
|
135
|
+
subject.has!('a','b').should == subject
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#clear' do
|
140
|
+
it 'removes all values' do
|
141
|
+
subject.put 'inputs', 'broke', 3
|
142
|
+
subject.clear
|
143
|
+
subject.has?('inputs','broke').should be_false
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe '#def_value' do
|
148
|
+
it 'stores given value when not present' do
|
149
|
+
subject.def_value 'inputs', 'shadoobie', 23
|
150
|
+
subject.get('inputs','shadoobie').should == 23
|
151
|
+
end
|
152
|
+
it "leaves stored value alone" do
|
153
|
+
subject.put 'inputs', 'shapoopie', 67
|
154
|
+
subject.def_value 'inputs', 'shapoopie', 23
|
155
|
+
subject.get('inputs','shapoopie').should == 67
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe '#def_values' do
|
160
|
+
it 'stores given value when not present' do
|
161
|
+
subject.def_values 'output', 100, 'zip', 'zap'
|
162
|
+
subject.get('output','zip').should == 100
|
163
|
+
subject.get('output','zap').should == 100
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
describe '#def_zero' do
|
168
|
+
it "stores zero when not present" do
|
169
|
+
subject.def_zero 'inputs', 'newbie'
|
170
|
+
subject.get('inputs','newbie').should == 0
|
171
|
+
end
|
172
|
+
it "leaves stored value alone" do
|
173
|
+
subject.put('inputs','boogie',23)
|
174
|
+
subject.def_zero 'inputs', 'boogie'
|
175
|
+
subject.get('inputs','boogie').should == 23
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe '#def_zeros' do
|
180
|
+
it "stores zeros when not present" do
|
181
|
+
subject.def_zeros({ 'animal' => 'cow', 'animal' => 'bear' })
|
182
|
+
subject.get('animal','bear').should == 0
|
183
|
+
subject.get('animal','cow').should == 0
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe '#decr' do
|
188
|
+
it "decrements stored value" do
|
189
|
+
subject.put 'inputs', 'lost', 100
|
190
|
+
subject.decr 'inputs', 'lost'
|
191
|
+
subject.get('inputs','lost').should == 99
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe '#incr' do
|
196
|
+
it "increments stored value" do
|
197
|
+
subject.put 'inputs', 'found', 100
|
198
|
+
subject.incr 'inputs', 'found'
|
199
|
+
subject.get('inputs','found').should == 101
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
describe '#decr_by' do
|
204
|
+
it 'decrements stored value by a given value' do
|
205
|
+
subject.put 'inputs', 'mu', 100
|
206
|
+
subject.decr_by 'inputs', 'mu', 3
|
207
|
+
subject.get('inputs','mu').should == 97
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
describe '#incr_by' do
|
212
|
+
it 'increments stored value by a given value' do
|
213
|
+
subject.put 'inputs', 'pu', 100
|
214
|
+
subject.incr_by 'inputs', 'pu', 3
|
215
|
+
subject.get('inputs','pu').should == 103
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe '#set_lt' do
|
220
|
+
it 'should set when less' do
|
221
|
+
subject.put 'particle', 'proton', 100
|
222
|
+
subject.set_lt 'particle', 'proton', 90
|
223
|
+
subject.get('particle','proton').should == 90
|
224
|
+
end
|
225
|
+
it 'should ignore when not less' do
|
226
|
+
subject.put 'particle', 'proton', 100
|
227
|
+
subject.set_lt 'particle', 'proton', 110
|
228
|
+
subject.get('particle','proton').should == 100
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
describe '#set_gt' do
|
233
|
+
it 'should set when greater' do
|
234
|
+
subject.put 'particle', 'proton', 100
|
235
|
+
subject.set_gt 'particle', 'proton', 110
|
236
|
+
subject.get('particle','proton').should == 110
|
237
|
+
end
|
238
|
+
it 'should ignore when not greater' do
|
239
|
+
subject.put 'particle', 'proton', 100
|
240
|
+
subject.set_gt 'particle', 'proton', 90
|
241
|
+
subject.get('particle','proton').should == 100
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def setup_fake_values
|
246
|
+
@stats.put 'a', 'b', 3
|
247
|
+
@stats.put 'c', 'd', 5
|
248
|
+
@expected_hash = { 'a' => { 'b' => 3 }, 'c' => { 'd' => 5 } }
|
249
|
+
end
|
250
|
+
def setup_fake_output
|
251
|
+
@out = stub_everything()
|
252
|
+
end
|
253
|
+
|
254
|
+
describe '#dump' do
|
255
|
+
before(:each) do setup_fake_values; setup_fake_output end
|
256
|
+
it 'outputs to formatter' do
|
257
|
+
subject.format.expects(:dump).with(@expected_hash,@out,'msg').once
|
258
|
+
subject.dump @out, 'msg'
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
describe '#flush' do
|
263
|
+
before(:each) do setup_fake_values; setup_fake_output end
|
264
|
+
it 'dumps to formatter' do
|
265
|
+
subject.expects(:dump).with(@out,'msg').once
|
266
|
+
subject.flush @out, 'msg'
|
267
|
+
end
|
268
|
+
it 'clears all values' do
|
269
|
+
subject.flush @out, 'msg'
|
270
|
+
subject.has?('a','b').should be_false
|
271
|
+
subject.has?('c','d').should be_false
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
describe '#log_dump' do
|
276
|
+
before(:each) do setup_fake_output end
|
277
|
+
it 'warns of deprecation' do
|
278
|
+
subject.expects(:warn).with(regexp_matches(%r{\[DEPRECATED\]})).once
|
279
|
+
subject.log_flush @out, 'msg'
|
280
|
+
end
|
281
|
+
it 'calls #dump' do
|
282
|
+
subject.expects(:warn).once
|
283
|
+
subject.expects(:dump).with(@out,'msg').once
|
284
|
+
subject.log_dump @out, 'msg'
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
describe '#log_flush' do
|
289
|
+
before(:each) do setup_fake_output end
|
290
|
+
it 'warns of deprecation' do
|
291
|
+
subject.expects(:warn).with(regexp_matches(%r{\[DEPRECATED\]})).once
|
292
|
+
subject.log_flush @out, 'msg'
|
293
|
+
end
|
294
|
+
it 'calls #flush' do
|
295
|
+
subject.expects(:warn).once
|
296
|
+
subject.expects(:flush).with(@out,'msg').once
|
297
|
+
subject.log_flush @out, 'msg'
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
end
|
302
|
+
end end end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'ghaki/stats/format/base'
|
2
|
+
|
3
|
+
module Ghaki module Stats module Format module Base_Testing
|
4
|
+
describe Ghaki::Stats::Format::Base do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
@subj = Format::Base.new
|
8
|
+
@stats = {}
|
9
|
+
@out = 'file'
|
10
|
+
@title = 'msg'
|
11
|
+
end
|
12
|
+
|
13
|
+
subject { @subj }
|
14
|
+
|
15
|
+
describe '#initialize' do
|
16
|
+
it 'accepts option :title' do
|
17
|
+
Format::Base.new( :title => 'msg' ).title.should == 'msg'
|
18
|
+
end
|
19
|
+
it 'defaults option: title' do
|
20
|
+
Format::Base.new().title.should == ''
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it { should respond_to :dump_head }
|
25
|
+
it { should respond_to :dump_body }
|
26
|
+
it { should respond_to :dump_tail }
|
27
|
+
|
28
|
+
describe '#dump' do
|
29
|
+
it 'dump header' do
|
30
|
+
subject.expects(:dump_head).with(@stats,@out,@title).once
|
31
|
+
subject.dump @stats, @out, @title
|
32
|
+
end
|
33
|
+
it 'dump stats body' do
|
34
|
+
subject.expects(:dump_body).with(@stats,@out,@title).once
|
35
|
+
subject.dump @stats, @out, @title
|
36
|
+
end
|
37
|
+
it 'dump footer' do
|
38
|
+
subject.expects(:dump_tail).with(@stats,@out,@title).once
|
39
|
+
subject.dump @stats, @out, @title
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end end end end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'ghaki/stats/format/logger'
|
2
|
+
require 'ghaki/logger/spec_helper'
|
3
|
+
|
4
|
+
module Ghaki module Stats module Format module Logger_Testing
|
5
|
+
describe Format::Logger do
|
6
|
+
include Ghaki::Logger::SpecHelper
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
setup_safe_logger
|
10
|
+
@subj = Format::Logger.new
|
11
|
+
@stats = {
|
12
|
+
'a' => { 'b' => 12 },
|
13
|
+
'c' => { 'd' => 34 },
|
14
|
+
}
|
15
|
+
@out = 'file'
|
16
|
+
@title = 'msg'
|
17
|
+
end
|
18
|
+
|
19
|
+
subject { @subj }
|
20
|
+
|
21
|
+
it { should be_kind_of(Format::Output) }
|
22
|
+
|
23
|
+
describe '#dump_head' do
|
24
|
+
context 'with no title' do
|
25
|
+
it 'logs start of dump' do
|
26
|
+
@logger.minor.expects(:began).with('dumping statistics').once
|
27
|
+
subject.dump_head @stats, @logger, ''
|
28
|
+
end
|
29
|
+
end
|
30
|
+
context 'with given title' do
|
31
|
+
it 'logs header title' do
|
32
|
+
@logger.expects(:box).with(@title).once
|
33
|
+
subject.dump_head @stats, @logger, @title
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#dump_tail' do
|
39
|
+
context 'with no title' do
|
40
|
+
it 'logs ending of dump' do
|
41
|
+
@logger.minor.expects(:ended).with('dumping statistics').once
|
42
|
+
subject.dump_tail @stats, @logger, ''
|
43
|
+
end
|
44
|
+
end
|
45
|
+
context 'with given title' do
|
46
|
+
it 'logs footer line' do
|
47
|
+
@logger.expects(:liner).once
|
48
|
+
subject.dump_tail @stats, @logger, @title
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end end end end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'ghaki/stats/format/null'
|
2
|
+
|
3
|
+
module Ghaki module Stats module Format module Null_Testing
|
4
|
+
describe Ghaki::Stats::Format::Null do
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
@subj = Format::Null.new
|
8
|
+
end
|
9
|
+
|
10
|
+
subject { @subj }
|
11
|
+
|
12
|
+
it { should be_kind_of(Format::Base) }
|
13
|
+
|
14
|
+
end
|
15
|
+
end end end end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'ghaki/stats/format/output'
|
2
|
+
require 'ghaki/logger/spec_helper'
|
3
|
+
|
4
|
+
module Ghaki module Stats module Format module Output_Testing
|
5
|
+
describe Format::Output do
|
6
|
+
include Ghaki::Logger::SpecHelper
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
setup_safe_logger
|
10
|
+
@subj = Format::Output.new
|
11
|
+
@stats = {
|
12
|
+
'a' => { 'b' => 12 },
|
13
|
+
'c' => { 'd' => 34 },
|
14
|
+
}
|
15
|
+
@out = 'file'
|
16
|
+
@title = 'msg'
|
17
|
+
end
|
18
|
+
|
19
|
+
subject { @subj }
|
20
|
+
|
21
|
+
it { should be_kind_of(Format::Base) }
|
22
|
+
|
23
|
+
describe '#dump_body' do
|
24
|
+
it 'writes output' do
|
25
|
+
subject.dump_body @stats, @logger, @title
|
26
|
+
@logger.with_file do |file|
|
27
|
+
file.rewind
|
28
|
+
file.read.split("\n").should == [
|
29
|
+
'# a:', sprintf('# %8s : %c', 12, 'b'),
|
30
|
+
'# c:', sprintf('# %8s : %s', 34, 'd'),
|
31
|
+
]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end end end end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
############################################################################
|
2
|
+
require 'ghaki/stats/mixin'
|
3
|
+
|
4
|
+
############################################################################
|
5
|
+
module Ghaki module Stats module MixinTesting
|
6
|
+
describe Ghaki::Stats::Mixin do
|
7
|
+
|
8
|
+
class UsingMixin
|
9
|
+
include Ghaki::Stats::Mixin
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'object including' do
|
13
|
+
subject { UsingMixin.new }
|
14
|
+
it { should respond_to :stats }
|
15
|
+
it { should respond_to :stats= }
|
16
|
+
end
|
17
|
+
|
18
|
+
context '#stats' do
|
19
|
+
subject { UsingMixin.new.stats }
|
20
|
+
specify { should be_an_instance_of(Ghaki::Stats::Base) }
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end end end
|
25
|
+
############################################################################
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'ghaki/stats/spec_helper'
|
2
|
+
|
3
|
+
module Ghaki module Stats module SpecHelper_Testing
|
4
|
+
describe SpecHelper do
|
5
|
+
include Ghaki::Stats::SpecHelper
|
6
|
+
|
7
|
+
class Fake < Stats::Base
|
8
|
+
end
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
@stats = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#make_safe_stats' do
|
15
|
+
it 'returns stats object' do
|
16
|
+
@stats = make_safe_stats()
|
17
|
+
@stats.should be_instance_of(Ghaki::Stats::Base)
|
18
|
+
end
|
19
|
+
it 'uses null sink for formatting' do
|
20
|
+
@stats = make_safe_stats()
|
21
|
+
@stats.format.should be_instance_of(Ghaki::Stats::Format::Null)
|
22
|
+
end
|
23
|
+
it 'accepts stats class' do
|
24
|
+
@stats = make_safe_stats(Fake)
|
25
|
+
@stats.should be_instance_of(Fake)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#setup_safe_stats' do
|
30
|
+
it 'creates stats member value' do
|
31
|
+
setup_safe_stats()
|
32
|
+
@stats.should be_instance_of(Ghaki::Stats::Base)
|
33
|
+
end
|
34
|
+
it 'accepts stats class' do
|
35
|
+
setup_safe_stats(Fake)
|
36
|
+
@stats.should be_instance_of(Fake)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end end end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ghaki-stats
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2011.11.29.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Gerald Kalafut
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-30 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ghaki-app
|
16
|
+
requirement: &85199070 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2011.11.29.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *85199070
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &85198850 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.4.0
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *85198850
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: mocha
|
38
|
+
requirement: &85198620 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.9.12
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *85198620
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rdoc
|
49
|
+
requirement: &85198390 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.9.4
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *85198390
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: ghaki-logger
|
60
|
+
requirement: &85198160 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 2011.11.29.1
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *85198160
|
69
|
+
description: Simple tracker for counted statistics.
|
70
|
+
email: gerald@kalafut.org
|
71
|
+
executables: []
|
72
|
+
extensions: []
|
73
|
+
extra_rdoc_files:
|
74
|
+
- README
|
75
|
+
files:
|
76
|
+
- lib/ghaki/stats/mixin.rb
|
77
|
+
- lib/ghaki/stats/format/output.rb
|
78
|
+
- lib/ghaki/stats/format/null.rb
|
79
|
+
- lib/ghaki/stats/format/logger.rb
|
80
|
+
- lib/ghaki/stats/format/base.rb
|
81
|
+
- lib/ghaki/stats/spec_helper.rb
|
82
|
+
- lib/ghaki/stats/errors.rb
|
83
|
+
- lib/ghaki/stats/app.rb
|
84
|
+
- lib/ghaki/stats/base.rb
|
85
|
+
- README
|
86
|
+
- LICENSE
|
87
|
+
- VERSION
|
88
|
+
- spec/ghaki/stats/base_spec.rb
|
89
|
+
- spec/ghaki/stats/spec_helper_spec.rb
|
90
|
+
- spec/ghaki/stats/app_stats_spec.rb
|
91
|
+
- spec/ghaki/stats/mixin_spec.rb
|
92
|
+
- spec/ghaki/stats/format/null_spec.rb
|
93
|
+
- spec/ghaki/stats/format/output_spec.rb
|
94
|
+
- spec/ghaki/stats/format/base_spec.rb
|
95
|
+
- spec/ghaki/stats/format/logger_spec.rb
|
96
|
+
- spec/ghaki/stats/app_engine_spec.rb
|
97
|
+
- spec/spec_helper.rb
|
98
|
+
homepage: http://github.com/ghaki
|
99
|
+
licenses: []
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: 1.3.6
|
116
|
+
requirements: []
|
117
|
+
rubyforge_project: ghaki-stats
|
118
|
+
rubygems_version: 1.8.10
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: Statistical tracking
|
122
|
+
test_files:
|
123
|
+
- spec/ghaki/stats/base_spec.rb
|
124
|
+
- spec/ghaki/stats/spec_helper_spec.rb
|
125
|
+
- spec/ghaki/stats/app_stats_spec.rb
|
126
|
+
- spec/ghaki/stats/mixin_spec.rb
|
127
|
+
- spec/ghaki/stats/format/null_spec.rb
|
128
|
+
- spec/ghaki/stats/format/output_spec.rb
|
129
|
+
- spec/ghaki/stats/format/base_spec.rb
|
130
|
+
- spec/ghaki/stats/format/logger_spec.rb
|
131
|
+
- spec/ghaki/stats/app_engine_spec.rb
|
132
|
+
- spec/spec_helper.rb
|