crunchr 0.0.1 → 0.0.2
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/VERSION +1 -1
- data/crunchr.gemspec +2 -2
- data/lib/crunchr.rb +75 -15
- data/spec/crunchr_spec.rb +19 -0
- metadata +15 -15
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
data/crunchr.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "crunchr"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Hartog C. de Mik"]
|
12
|
-
s.date = "2013-02-
|
12
|
+
s.date = "2013-02-11"
|
13
13
|
s.description = "Crunch statistics"
|
14
14
|
s.email = "hartog@organisedminds.com"
|
15
15
|
s.extra_rdoc_files = [
|
data/lib/crunchr.rb
CHANGED
@@ -77,9 +77,29 @@ module Crunchr
|
|
77
77
|
|
78
78
|
# given a string like 'keys - doors', returns the amount of spare keys
|
79
79
|
#
|
80
|
+
# You can group calculations by surrounding them with (), eg:
|
81
|
+
#
|
82
|
+
# (doors - keys) / (inhabitants - keys)
|
83
|
+
#
|
84
|
+
# Pass in real numbers if you like
|
85
|
+
#
|
86
|
+
# (doors + 2) / keys
|
87
|
+
#
|
88
|
+
# @note
|
89
|
+
# The result is *always* a float.
|
90
|
+
# If anything fails, 0.0 is returned.
|
91
|
+
#
|
92
|
+
# @param String key The calculation to perform
|
93
|
+
# @return Float result
|
94
|
+
#
|
80
95
|
def calculate(key)
|
81
|
-
(
|
96
|
+
while key =~ /\(/ && key =~ /\)/
|
97
|
+
key.gsub!(/\(([^\(\)]+)\)/) do |calculation|
|
98
|
+
calculate(calculation.gsub(/[\(\)]/, ''))
|
99
|
+
end
|
100
|
+
end
|
82
101
|
|
102
|
+
(left, op, right) = key.split(/\s/)
|
83
103
|
|
84
104
|
left = (
|
85
105
|
left =~ /[^\d.]/ ? self.fetch(left) : BigDecimal.new(left)
|
@@ -101,33 +121,51 @@ module Crunchr
|
|
101
121
|
|
102
122
|
module ClassMethods
|
103
123
|
# pass in a list off data-objects with and get a nice table
|
104
|
-
# list = [ Object.data({ doors: 1, keys: 2}),
|
124
|
+
# list = [ Object.data({ doors: 1, keys: 2}),
|
125
|
+
# Object.data({ doors: 1, keys: 3 },
|
126
|
+
# ...
|
127
|
+
# ]
|
105
128
|
#
|
106
129
|
# table = Object.as_table(list, keys: %w[doors keys])
|
107
130
|
# # => [ [ 1, 2 ], [ 1, 3 ], [ 1, 4 ], [ 3, 8 ] ]
|
108
131
|
#
|
109
132
|
# Or use lists in lists
|
133
|
+
#
|
110
134
|
# deep_list = [ list, list list ]
|
111
|
-
# table = Object.as_table(
|
112
|
-
#
|
135
|
+
# table = Object.as_table(
|
136
|
+
# deep_list, keys: %[doors keys], list_operator: delta
|
137
|
+
# )
|
138
|
+
# # => [ [ 2, 6 ] ] (difference of max and min for both doors and keys)
|
139
|
+
#
|
140
|
+
# == Usage with dates/times
|
141
|
+
#
|
142
|
+
# If you include Crunchr into something Active-Modely that has 'created_at'
|
143
|
+
# as a (sane) attribute, you can supply a :date key, it will add a column
|
144
|
+
# with the value of created_at into the table. If you do not supply
|
145
|
+
# :date_fmt, it will call #to_date on the column
|
113
146
|
#
|
114
147
|
# @param [Array] list List (1d or 2d) of data objects
|
115
148
|
# @param [Hash] opts Options
|
116
149
|
# @option opts [Array] keys List of keys to fetch, may contain
|
117
150
|
# calculations, eg: ['doors', 'keys', 'doors / keys']
|
118
|
-
# @option opts [Symbol] list_operator
|
119
|
-
# apply to each given list to determine the 1d value
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
127
|
-
#
|
151
|
+
# @option opts [Symbol] list_operator With a 2d list, what operator to
|
152
|
+
# apply to each given list to determine the 1d value see #delta for
|
153
|
+
# more info
|
154
|
+
# @option opts [String] date_fmt Use as input to #strftime for the value
|
155
|
+
# in the date column
|
156
|
+
# @option opts [String] str_fmt Use as input to #sprintf for the value
|
157
|
+
# in **every** column. (Cannot be used together with :delta)
|
158
|
+
# @option opts [Boolean] delta After the first row, fill every other row
|
159
|
+
# with the difference to the previous row. (Cannot be used with
|
160
|
+
# :str_fmt)
|
161
|
+
#
|
128
162
|
def as_table(list, opts = {})
|
129
163
|
keys = opts[:keys] || raise("Need keys")
|
130
164
|
|
165
|
+
if opts[:delta] && opts[:str_fmt]
|
166
|
+
raise ":delta and :str_fmt cannot be supplied together"
|
167
|
+
end
|
168
|
+
|
131
169
|
table = []
|
132
170
|
|
133
171
|
list.each do |statistic|
|
@@ -188,6 +226,23 @@ module Crunchr
|
|
188
226
|
return table
|
189
227
|
end
|
190
228
|
|
229
|
+
# flatten an array of rows by applying an operator vertically on each
|
230
|
+
# column and accepting the result as a single row
|
231
|
+
#
|
232
|
+
# @param [Array] array List of lists
|
233
|
+
# @param [Hash] opts Options
|
234
|
+
# @option opts [Symbol] list_operator What operator to apply to the array
|
235
|
+
# to get a single value, defaults to :mean, should be any of
|
236
|
+
# - :mean
|
237
|
+
# - :stddev
|
238
|
+
# - :median
|
239
|
+
# - :range
|
240
|
+
# - :mode
|
241
|
+
# - :sum
|
242
|
+
# - :min
|
243
|
+
# - :max
|
244
|
+
# - :delta (takes the difference of max and min)
|
245
|
+
#
|
191
246
|
def flatten(array, opts)
|
192
247
|
keys = opts[:keys].dup
|
193
248
|
|
@@ -229,11 +284,16 @@ module Crunchr
|
|
229
284
|
return [keys, collection]
|
230
285
|
end
|
231
286
|
|
232
|
-
|
287
|
+
# Return a BigDecimal zero value
|
233
288
|
def zero
|
234
289
|
BigDecimal.new("0.0")
|
235
290
|
end
|
236
291
|
|
292
|
+
# Make sure the value is zero if it is NaN, infinite, or nil
|
293
|
+
# Turn the value into a float if it is a BigDecimal
|
294
|
+
#
|
295
|
+
# @param value The value to check
|
296
|
+
# @return [Float, Integer] the improved value
|
237
297
|
def checked(value)
|
238
298
|
value = zero() if value.respond_to?(:nan?) && value.nan?
|
239
299
|
value = zero() if value.respond_to?(:infinity?) && value.infinity?
|
data/spec/crunchr_spec.rb
CHANGED
@@ -164,4 +164,23 @@ describe "Crunchr" do
|
|
164
164
|
end
|
165
165
|
|
166
166
|
end
|
167
|
+
|
168
|
+
context "Extended calculations" do
|
169
|
+
before(:each) do
|
170
|
+
subject.data = deep_hash
|
171
|
+
end
|
172
|
+
|
173
|
+
it "performs calculations successively" do
|
174
|
+
subject.fetch("(loans/requested/GBP + loans/payed/GBP) - commission/pending/GBP").should == (0.65395 + 145.23) - 1.3079
|
175
|
+
end
|
176
|
+
|
177
|
+
it "handles nested groupings" do
|
178
|
+
subject.fetch("((users/count + users/active) + users/active) + users/count").should == (((14 + 2) + 2) + 14).to_f
|
179
|
+
end
|
180
|
+
|
181
|
+
it "ignores malformed groupings" do
|
182
|
+
subject.fetch("(users/count + users/active").should == 2.0 # 0 + 2
|
183
|
+
subject.fetch("((users/count + users/active) + 12").should == 12.0
|
184
|
+
end
|
185
|
+
end
|
167
186
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crunchr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &24262560 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '2.12'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *24262560
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: mocha
|
27
|
-
requirement: &
|
27
|
+
requirement: &24290860 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *24290860
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rdoc
|
38
|
-
requirement: &
|
38
|
+
requirement: &24297100 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '3.12'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *24297100
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: bundler
|
49
|
-
requirement: &
|
49
|
+
requirement: &24305540 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - =
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 1.2.1
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *24305540
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: jeweler
|
60
|
-
requirement: &
|
60
|
+
requirement: &24329100 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 1.8.4
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *24329100
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rcov
|
71
|
-
requirement: &
|
71
|
+
requirement: &24375820 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *24375820
|
80
80
|
description: Crunch statistics
|
81
81
|
email: hartog@organisedminds.com
|
82
82
|
executables: []
|
@@ -114,7 +114,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
114
114
|
version: '0'
|
115
115
|
segments:
|
116
116
|
- 0
|
117
|
-
hash:
|
117
|
+
hash: -971526191153423674
|
118
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
119
|
none: false
|
120
120
|
requirements:
|