pivotable 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/README.markdown ADDED
@@ -0,0 +1,3 @@
1
+ # Pivotable
2
+
3
+ TODO
@@ -0,0 +1,17 @@
1
+ class Pivotable::Collection < Hash
2
+
3
+ attr_reader :model
4
+
5
+ def initialize(model)
6
+ @model = model
7
+ super()
8
+ end
9
+
10
+ # Adds a new rotation to this collection
11
+ def rotation(name, &block)
12
+ name, parent = name.is_a?(Hash) ? name.to_a.first : [name, nil]
13
+ item = Pivotable::Rotation.new(self, name, parent, &block)
14
+ self[item.name] = item
15
+ end
16
+
17
+ end
@@ -0,0 +1,35 @@
1
+ class Pivotable::Column
2
+
3
+ attr_reader :attribute
4
+
5
+ def initialize(model, attribute, options = {})
6
+ @as = options[:as]
7
+ @attribute = case attribute
8
+ when Arel::Attribute
9
+ attribute
10
+ else
11
+ model.arel_table[attribute]
12
+ end
13
+ raise ArgumentError, "Invalid attribute #{attribute.inspect}" unless @attribute
14
+ end
15
+
16
+ def name
17
+ @as || attribute.name
18
+ end
19
+
20
+ def calculate!(function)
21
+ @as ||= attribute.name
22
+ @function = attribute.send(function)
23
+ end
24
+
25
+ def to_select
26
+ select = (@function || attribute).clone
27
+ select.as(@as.to_s) if @as
28
+ select
29
+ end
30
+
31
+ def to_group
32
+ attribute.clone
33
+ end
34
+
35
+ end
@@ -0,0 +1,55 @@
1
+ # Includable module, for ActiveRecord::Base
2
+ module Pivotable::Model
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ class_attribute :_pivotable
7
+ self._pivotable = {}
8
+ end
9
+
10
+ module ClassMethods
11
+
12
+ # Pivotable definition for a model. Example:
13
+ #
14
+ # class Stat < ActiveRecord::Base
15
+ #
16
+ # # Add your rotations
17
+ # pivotable do
18
+ #
19
+ # rotation :overall do
20
+ # sum :visits
21
+ # end
22
+ #
23
+ # # Rotations can in herit parent definitions
24
+ # rotation :by_day => :overall do
25
+ # by :day
26
+ # end
27
+ #
28
+ # end
29
+ #
30
+ # # Add your custom rotations, e.g. for admins
31
+ # pivotable :admin do
32
+ #
33
+ # rotation :overall do
34
+ # sum :visits
35
+ # maximum :bounce_rate
36
+ # end
37
+ #
38
+ # end
39
+ #
40
+ # end
41
+ #
42
+ def pivotable(name = nil, &block)
43
+ name = name.present? ? name.to_sym : :_default
44
+ _pivotable[name] ||= Pivotable::Collection.new(self)
45
+ _pivotable[name.to_sym].instance_eval(&block) if block
46
+ _pivotable[name]
47
+ end
48
+
49
+ # Delegator to Relation#pivot
50
+ def pivot(*args)
51
+ scoped.pivot(*args)
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,19 @@
1
+ module Pivotable::Pivoting
2
+
3
+ # Apply pivot retations. Example:
4
+ #
5
+ # Stat.pivot(:overall)
6
+ #
7
+ # # Use custom (e.g. admin) rotation
8
+ # Stat.pivot(:admin, :by_day)
9
+ #
10
+ # # Combine it with relations & scopes
11
+ # Stat.latest.order('some_column').pivot(:by_day).paginate :page => 1
12
+ #
13
+ def pivot(*args)
14
+ rotation = args.pop
15
+ scope = args.first.is_a?(Symbol) ? args.shift : nil
16
+ klass.pivotable(scope)[rotation].merge(self)
17
+ end
18
+
19
+ end
@@ -0,0 +1,86 @@
1
+ class Pivotable::Rotation
2
+
3
+ attr_reader :collection, :name, :parent, :block, :selects, :groups, :joins, :loaded
4
+ delegate :model, :to => :collection
5
+ alias :loaded? :loaded
6
+
7
+ def initialize(collection, name, parent = nil, &block)
8
+ @collection = collection
9
+ @name = name.to_sym
10
+ @parent = parent.to_sym if parent
11
+ @selects = []
12
+ @groups = []
13
+ @joins = []
14
+ @block = block
15
+ @loaded = false
16
+ end
17
+
18
+ def sum(*cols)
19
+ calculate :sum, *cols
20
+ end
21
+
22
+ def minimum(*cols)
23
+ calculate :minimum, *cols
24
+ end
25
+
26
+ def maximum(*cols)
27
+ calculate :maximum, *cols
28
+ end
29
+
30
+ def average(*cols)
31
+ calculate :average, *cols
32
+ end
33
+
34
+ def by(*cols)
35
+ cols = columns(*cols)
36
+ @selects += cols
37
+ @groups += cols
38
+ end
39
+
40
+ def calculate(function, *cols)
41
+ columns(*cols).each do |col|
42
+ col.calculate!(function)
43
+ @selects << col
44
+ end
45
+ end
46
+
47
+ def joins(*names)
48
+ @joins += names
49
+ end
50
+
51
+ def merge(relation)
52
+ load! unless loaded?
53
+
54
+ selects.each do |column|
55
+ relation = relation.select(column.to_select)
56
+ end
57
+
58
+ groups.each do |column|
59
+ relation = relation.group(column.to_group)
60
+ end
61
+
62
+ joins.each do |join|
63
+ relation = relation.joins(join)
64
+ end
65
+
66
+ relation
67
+ end
68
+
69
+ private
70
+
71
+ def load!
72
+ return if loaded?
73
+
74
+ instance_eval &collection[parent].block if parent
75
+ instance_eval &block
76
+ @loaded = true
77
+ end
78
+
79
+ def columns(*cols)
80
+ opts = cols.extract_options!
81
+ cols.map do |col|
82
+ Pivotable::Column.new(model, col, opts)
83
+ end
84
+ end
85
+
86
+ end
data/lib/pivotable.rb ADDED
@@ -0,0 +1,19 @@
1
+ require "active_support/core_ext"
2
+ require "active_record"
3
+ require "active_record/relation"
4
+
5
+ module Pivotable
6
+ autoload :Model, "pivotable/model"
7
+ autoload :Pivoting, "pivotable/pivoting"
8
+ autoload :Rotation, "pivotable/rotation"
9
+ autoload :Column, "pivotable/column"
10
+ autoload :Collection, "pivotable/collection"
11
+ end
12
+
13
+ ActiveRecord::Base.class_eval do
14
+ include ::Pivotable::Model
15
+ end
16
+
17
+ ActiveRecord::Relation.class_eval do
18
+ include ::Pivotable::Pivoting
19
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pivotable
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Dimitrij Denissenko
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-07-05 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: abstract
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: activerecord
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 7
44
+ segments:
45
+ - 3
46
+ - 0
47
+ - 0
48
+ version: 3.0.0
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: activesupport
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 7
60
+ segments:
61
+ - 3
62
+ - 0
63
+ - 0
64
+ version: 3.0.0
65
+ type: :runtime
66
+ version_requirements: *id003
67
+ description: Great for building APIs & reports
68
+ email: dimitrij@blacksquaremedia.com
69
+ executables: []
70
+
71
+ extensions: []
72
+
73
+ extra_rdoc_files: []
74
+
75
+ files:
76
+ - README.markdown
77
+ - lib/pivotable/pivoting.rb
78
+ - lib/pivotable/column.rb
79
+ - lib/pivotable/collection.rb
80
+ - lib/pivotable/rotation.rb
81
+ - lib/pivotable/model.rb
82
+ - lib/pivotable.rb
83
+ has_rdoc: true
84
+ homepage: https://github.com/bsm/pivotable
85
+ licenses: []
86
+
87
+ post_install_message:
88
+ rdoc_options: []
89
+
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ hash: 57
98
+ segments:
99
+ - 1
100
+ - 8
101
+ - 7
102
+ version: 1.8.7
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ hash: 23
109
+ segments:
110
+ - 1
111
+ - 3
112
+ - 6
113
+ version: 1.3.6
114
+ requirements: []
115
+
116
+ rubyforge_project:
117
+ rubygems_version: 1.6.2
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: Build pivotable data tables with ActiveRecord
121
+ test_files: []
122
+