totalr 0.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.
- data/.gitignore +4 -0
- data/Gemfile +6 -0
- data/README +24 -0
- data/Rakefile +6 -0
- data/lib/totalr/version.rb +3 -0
- data/lib/totalr.rb +72 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/totalr_spec.rb +193 -0
- data/totalr.gemspec +25 -0
- metadata +58 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Totalr is a ruby library which gives a dsl that lets you do aggregations in your model declaratively.
|
2
|
+
It is inspired by the statistical capabilities of R. Currently it does not even do 1 % of what R does.
|
3
|
+
|
4
|
+
But it still lets you do aggregations like totaling, percentage, grouping in your model easily:
|
5
|
+
|
6
|
+
class Team
|
7
|
+
total :players, using: :goals, by: :age
|
8
|
+
end
|
9
|
+
|
10
|
+
This creates a dynamic method total_player_goals_by_age which takes an age param.
|
11
|
+
|
12
|
+
class Team
|
13
|
+
percentage :total_player_goals, of: :total_player_attempts, as: :goals_to_attempts
|
14
|
+
end
|
15
|
+
|
16
|
+
This creates a method which calculates percentage of goals:attempts for all players in the model.
|
17
|
+
|
18
|
+
Totalr does not serve to replace any aggregation mechanism already provided by ORM or Enumerable.
|
19
|
+
It only complements them by generating methods like this.
|
20
|
+
|
21
|
+
You can give custom names to generated methods using :as key
|
22
|
+
For documentation/features look at spec/totalr_spec.rb
|
23
|
+
|
24
|
+
More features like mean, variance are still under development.
|
data/Rakefile
ADDED
data/lib/totalr.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
|
3
|
+
module Totalr
|
4
|
+
def self.included(klass)
|
5
|
+
klass.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def total(coll_name, options = {})
|
10
|
+
attribute = options[:using]
|
11
|
+
group_by = options[:by]
|
12
|
+
method_name = options[:as]
|
13
|
+
method_name ||= "total_#{ActiveSupport::Inflector.singularize(coll_name.to_s)}_#{attribute}_for_#{group_by}" if attribute and group_by
|
14
|
+
method_name ||= "total_#{ActiveSupport::Inflector.singularize(coll_name.to_s)}_#{attribute}" if attribute
|
15
|
+
method_name ||= "total_#{coll_name}_for_#{group_by}" if group_by
|
16
|
+
method_name ||= "total_#{coll_name}"
|
17
|
+
|
18
|
+
method_body = if group_by
|
19
|
+
if attribute
|
20
|
+
lambda do |group_value|
|
21
|
+
coll = send(coll_name)
|
22
|
+
coll.select {|e| e.send(group_by) == group_value}.map {|e| e.send(attribute)}.inject(:+)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
lambda do |group_value|
|
26
|
+
coll = send(coll_name)
|
27
|
+
coll.select {|e| e.send(group_by) == group_value}.length
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
else
|
32
|
+
if attribute
|
33
|
+
lambda do
|
34
|
+
coll = send(coll_name)
|
35
|
+
coll.map {|e| e.send(attribute)}.inject(:+)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
lambda do
|
39
|
+
coll = send(coll_name)
|
40
|
+
coll.length
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
define_method method_name, method_body
|
45
|
+
end
|
46
|
+
|
47
|
+
def percentage(part_count_method, options = {})
|
48
|
+
total_count_method = options[:of]
|
49
|
+
part_by = options[:by]
|
50
|
+
total_by = options[:total_by]
|
51
|
+
|
52
|
+
method_name = options[:as]
|
53
|
+
method_name ||= "percentage_#{part_count_method}_in_#{total_by}" if total_by
|
54
|
+
method_name ||= "percentage_#{part_count_method}"
|
55
|
+
|
56
|
+
if total_by and total_by != part_by
|
57
|
+
define_method method_name do |part_by_value, total_by_value|
|
58
|
+
part_count = send(part_count_method, part_by_value)
|
59
|
+
total_count = total_by ? send(total_count_method, total_by_value) : send(total_count_method)
|
60
|
+
part_count * 100.00 / total_count
|
61
|
+
end
|
62
|
+
|
63
|
+
else
|
64
|
+
define_method method_name do |part_by_value|
|
65
|
+
part_count = send(part_count_method, part_by_value)
|
66
|
+
total_count = total_by ? send(total_count_method, part_by_value) : send(total_count_method)
|
67
|
+
part_count * 100.00 / total_count
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/totalr_spec.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe Totalr do
|
5
|
+
|
6
|
+
class Team
|
7
|
+
include Totalr
|
8
|
+
attr_accessor :players
|
9
|
+
|
10
|
+
def initialize(params)
|
11
|
+
@name = params[:name]
|
12
|
+
@players = []
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Player
|
17
|
+
attr_reader :goals
|
18
|
+
attr_reader :attempts
|
19
|
+
attr_reader :age
|
20
|
+
attr_reader :region
|
21
|
+
def initialize(params)
|
22
|
+
@name = params[:name]
|
23
|
+
@goals = params[:goals]
|
24
|
+
@attempts = params[:attempts]
|
25
|
+
@age = params[:age]
|
26
|
+
@region = params[:region]
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "total" do
|
32
|
+
|
33
|
+
class Team
|
34
|
+
total :players
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should total collection" do
|
38
|
+
real_madrid = Team.new(name: 'Real Madrid')
|
39
|
+
real_madrid.players << Player.new(name: 'Ronaldo')
|
40
|
+
real_madrid.players << Player.new(name: 'Beckham')
|
41
|
+
|
42
|
+
real_madrid.total_players.should == 2
|
43
|
+
end
|
44
|
+
|
45
|
+
class Team
|
46
|
+
total :players, as: :player_count
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should total collection with custom name" do
|
50
|
+
real_madrid = Team.new(name: 'Real Madrid')
|
51
|
+
real_madrid.players << Player.new(name: 'Ronaldo')
|
52
|
+
real_madrid.players << Player.new(name: 'Beckham')
|
53
|
+
|
54
|
+
real_madrid.player_count.should == 2
|
55
|
+
end
|
56
|
+
|
57
|
+
class Team
|
58
|
+
total :players, using: :goals
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should total collection using attribute" do
|
62
|
+
real_madrid = Team.new(name: 'Real Madrid')
|
63
|
+
real_madrid.players << Player.new(name: 'Ronaldo', goals: 25)
|
64
|
+
real_madrid.players << Player.new(name: 'Beckham', goals: 15)
|
65
|
+
|
66
|
+
real_madrid.total_player_goals.should == 40
|
67
|
+
end
|
68
|
+
|
69
|
+
class Team
|
70
|
+
total :players, using: :goals, as: :number_of_goals
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should total collection using attribute with custom name" do
|
74
|
+
real_madrid = Team.new(name: 'Real Madrid')
|
75
|
+
real_madrid.players << Player.new(name: 'Ronaldo', goals: 25)
|
76
|
+
real_madrid.players << Player.new(name: 'Beckham', goals: 15)
|
77
|
+
|
78
|
+
real_madrid.number_of_goals.should == 40
|
79
|
+
end
|
80
|
+
|
81
|
+
class Team
|
82
|
+
total :players, by: :age
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should total collection grouping by attribute" do
|
86
|
+
real_madrid = Team.new(name: 'Real Madrid')
|
87
|
+
real_madrid.players << Player.new(name: 'Ronaldo', age: 25)
|
88
|
+
real_madrid.players << Player.new(name: 'Beckham', age: 25)
|
89
|
+
real_madrid.players << Player.new(name: 'Figo', age: 30)
|
90
|
+
|
91
|
+
real_madrid.total_players_for_age(25).should == 2
|
92
|
+
real_madrid.total_players_for_age(30).should == 1
|
93
|
+
end
|
94
|
+
|
95
|
+
class Team
|
96
|
+
total :players, using: :goals, by: :age
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should total collection mapping by attribute and grouping by attribute" do
|
100
|
+
real_madrid = Team.new(name: 'Real Madrid')
|
101
|
+
real_madrid.players << Player.new(name: 'Ronaldo', goals: 25, age: 25)
|
102
|
+
real_madrid.players << Player.new(name: 'Beckham', goals: 15, age: 25)
|
103
|
+
real_madrid.players << Player.new(name: 'Figo', goals: 10, age: 30)
|
104
|
+
|
105
|
+
real_madrid.total_player_goals_for_age(25).should == 40
|
106
|
+
real_madrid.total_player_goals_for_age(30).should == 10
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "percentage" do
|
112
|
+
class Team
|
113
|
+
total :players
|
114
|
+
total :players, by: :age
|
115
|
+
percentage :total_players_for_age, by: :age, of: :total_players
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should calculate percentage of total" do
|
119
|
+
real_madrid = Team.new(name: 'Real Madrid')
|
120
|
+
real_madrid.players << Player.new(name: 'Ronaldo', age: 25)
|
121
|
+
real_madrid.players << Player.new(name: 'Beckham', age: 25)
|
122
|
+
real_madrid.players << Player.new(name: 'Figo', age: 30)
|
123
|
+
|
124
|
+
real_madrid.percentage_total_players_for_age(25).round(2).should == 66.67
|
125
|
+
real_madrid.percentage_total_players_for_age(30).round(2).should == 33.33
|
126
|
+
end
|
127
|
+
|
128
|
+
class Team
|
129
|
+
percentage :total_players_for_age, by: :age, of: :total_players, as: :distribution_by_age
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should calculate percentage of total with custom name" do
|
133
|
+
real_madrid = Team.new(name: 'Real Madrid')
|
134
|
+
real_madrid.players << Player.new(name: 'Ronaldo', age: 25)
|
135
|
+
real_madrid.players << Player.new(name: 'Beckham', age: 25)
|
136
|
+
real_madrid.players << Player.new(name: 'Figo', age: 30)
|
137
|
+
|
138
|
+
real_madrid.distribution_by_age(25).round(2).should == 66.67
|
139
|
+
real_madrid.distribution_by_age(30).round(2).should == 33.33
|
140
|
+
end
|
141
|
+
|
142
|
+
class Team
|
143
|
+
percentage :total_player_goals_for_age, by: :age, of: :total_player_goals, as: :percentage_goals_by_age
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should calculate percentage of total using attribute" do
|
147
|
+
real_madrid = Team.new(name: 'Real Madrid')
|
148
|
+
real_madrid.players << Player.new(name: 'Ronaldo', goals: 25, age: 25)
|
149
|
+
real_madrid.players << Player.new(name: 'Beckham', goals: 15, age: 25)
|
150
|
+
real_madrid.players << Player.new(name: 'Figo', goals: 10, age: 30)
|
151
|
+
|
152
|
+
real_madrid.percentage_goals_by_age(25).should == 80.00
|
153
|
+
real_madrid.percentage_goals_by_age(30).should == 20.00
|
154
|
+
end
|
155
|
+
|
156
|
+
class Team
|
157
|
+
total :players, using: :goals, by: :region
|
158
|
+
percentage :total_player_goals_for_age, by: :age,
|
159
|
+
of: :total_player_goals_for_region, total_by: :region
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should calculate percentage totaling by attribute" do
|
163
|
+
real_madrid = Team.new(name: 'Real Madrid')
|
164
|
+
real_madrid.players << Player.new(name: 'Ronaldo', goals: 25, age: 28, region: 'southamerica')
|
165
|
+
real_madrid.players << Player.new(name: 'Beckham', goals: 20, age: 25, region: 'europe')
|
166
|
+
real_madrid.players << Player.new(name: 'Carlos', goals: 10, age: 28, region: 'southamerica')
|
167
|
+
real_madrid.players << Player.new(name: 'Figo', goals: 12, age: 30, region: 'europe')
|
168
|
+
real_madrid.players << Player.new(name: 'Zidane', goals: 18, age: 30, region: 'europe')
|
169
|
+
|
170
|
+
real_madrid.percentage_total_player_goals_for_age_in_region(30, 'europe').should == 60.00
|
171
|
+
real_madrid.percentage_total_player_goals_for_age_in_region(25, 'europe').should == 40.00
|
172
|
+
end
|
173
|
+
|
174
|
+
class Team
|
175
|
+
total :players, using: :goals, by: :age
|
176
|
+
total :players, using: :attempts, by: :age
|
177
|
+
percentage :total_player_goals_for_age, by: :age,
|
178
|
+
of: :total_player_attempts_for_age, total_by: :age,
|
179
|
+
as: :goal_to_attempts
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should calculate percentage totaling by same attribute as percentage" do
|
184
|
+
real_madrid = Team.new(name: 'Real Madrid')
|
185
|
+
real_madrid.players << Player.new(name: 'Ronaldo', goals: 21, attempts: 30, age: 25)
|
186
|
+
real_madrid.players << Player.new(name: 'Beckham', goals: 15, attempts: 20, age: 25)
|
187
|
+
real_madrid.players << Player.new(name: 'Figo', goals: 10, attempts: 15, age: 30)
|
188
|
+
|
189
|
+
real_madrid.goal_to_attempts(25).should == 72.00
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
data/totalr.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "totalr/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "totalr"
|
7
|
+
s.version = Totalr::VERSION
|
8
|
+
s.authors = ["Sathish"]
|
9
|
+
s.email = ["sathish316@gmail.com"]
|
10
|
+
s.homepage = "http://www.github.com/sathish316/totalr"
|
11
|
+
s.summary = %q{Totalr is a lib which provides a simple dsl to do aggregation in models, like totals, percentage, grouping, mean, variance et
|
12
|
+
c}
|
13
|
+
s.description = %q{Totalr is a lib which provides a simple dsl to do aggregation in models, like totals, percentage, grouping, mean, variance et
|
14
|
+
c}
|
15
|
+
s.rubyforge_project = "totalr"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
# specify any dependencies here; for example:
|
23
|
+
# s.add_development_dependency "rspec"
|
24
|
+
# s.add_runtime_dependency "rest-client"
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: totalr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sathish
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-09-05 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! 'Totalr is a lib which provides a simple dsl to do aggregation in models,
|
15
|
+
like totals, percentage, grouping, mean, variance et
|
16
|
+
|
17
|
+
c'
|
18
|
+
email:
|
19
|
+
- sathish316@gmail.com
|
20
|
+
executables: []
|
21
|
+
extensions: []
|
22
|
+
extra_rdoc_files: []
|
23
|
+
files:
|
24
|
+
- .gitignore
|
25
|
+
- Gemfile
|
26
|
+
- README
|
27
|
+
- Rakefile
|
28
|
+
- lib/totalr.rb
|
29
|
+
- lib/totalr/version.rb
|
30
|
+
- spec/spec_helper.rb
|
31
|
+
- spec/totalr_spec.rb
|
32
|
+
- totalr.gemspec
|
33
|
+
homepage: http://www.github.com/sathish316/totalr
|
34
|
+
licenses: []
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
none: false
|
47
|
+
requirements:
|
48
|
+
- - ! '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
requirements: []
|
52
|
+
rubyforge_project: totalr
|
53
|
+
rubygems_version: 1.8.6
|
54
|
+
signing_key:
|
55
|
+
specification_version: 3
|
56
|
+
summary: Totalr is a lib which provides a simple dsl to do aggregation in models,
|
57
|
+
like totals, percentage, grouping, mean, variance et c
|
58
|
+
test_files: []
|