totalr 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|