calculable_attrs 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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +21 -0
- data/lib/calculable_attrs/active_record/base.rb +77 -0
- data/lib/calculable_attrs/active_record/querying.rb +3 -0
- data/lib/calculable_attrs/active_record/relation.rb +121 -0
- data/lib/calculable_attrs/active_record.rb +5 -0
- data/lib/calculable_attrs/calculator.rb +85 -0
- data/lib/calculable_attrs/model_calculable_attrs_scope.rb +58 -0
- data/lib/calculable_attrs/version.rb +3 -0
- data/lib/calculable_attrs.rb +9 -0
- data/lib/tasks/calculable_tasks.rake +4 -0
- metadata +128 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e0b5dd4bb3612fe4d97e9abf8c246d1e2e0fc540
|
4
|
+
data.tar.gz: c1f98f2e019eff2f6caa8b2a973f432a991b1512
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 531805fd07f189896eed424f7613469fc3c7b16cd36f79997fbe7624bcec6551edd0aa6cf7430d232e755d5663a7c5f69946a6df7a1167df29128bd90e4f748f
|
7
|
+
data.tar.gz: 19a1fd7a6a42b6047a852e7bb746324708b5e733f5b1dc88049f61dc99026ae1bd3192cd8a79294931defdefec2e6664cfe97c04baff3a72dde8e431f86f832d
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2014 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'CalculableAttrs'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
Bundler::GemHelper.install_tasks
|
21
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module CalculableAttrs::ActiveRecord::Base
|
2
|
+
module ClassMethods
|
3
|
+
def calculable_attr(attrs, &block)
|
4
|
+
relation = block ? lambda(&block) : attrs.delete(:from)
|
5
|
+
raise "CALCULABLE_ATTRS: Relation was missed." unless relation
|
6
|
+
|
7
|
+
foreign_key = attrs.delete(:foreign_key) || "#{ name.tableize }.id"
|
8
|
+
raise "CALCULABLE_ATTRS: At least one calculable attribute required." if attrs.empty?
|
9
|
+
|
10
|
+
calculator = CalculableAttrs::Calculator.new(foreign_key: foreign_key, relation: relation, attributes: attrs)
|
11
|
+
|
12
|
+
attrs.keys.each do |k|
|
13
|
+
calculable_attrs_calculators[k.to_sym] = calculator
|
14
|
+
class_eval <<-ruby
|
15
|
+
def #{ k }
|
16
|
+
calculable_attr_value(:#{ k })
|
17
|
+
end
|
18
|
+
ruby
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def calculable_attrs_calculators
|
23
|
+
@calculable_attrs_calculators ||= {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def calculable_attrs
|
27
|
+
calculable_attrs_calculators.keys
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.included(base)
|
32
|
+
base.extend(ClassMethods)
|
33
|
+
end
|
34
|
+
|
35
|
+
def calculable_attr_value(name)
|
36
|
+
name = name.to_sym
|
37
|
+
check_calculable_attr_name!(name)
|
38
|
+
unless calculable_attrs_calculated_flags[name]
|
39
|
+
recalc_calculable_attr_with_siblings(name)
|
40
|
+
end
|
41
|
+
calculable_attrs_values[name]
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_calculable_attr_value(name, value)
|
45
|
+
name = name.to_sym
|
46
|
+
check_calculable_attr_name!(name)
|
47
|
+
calculable_attrs_calculated_flags[name] = true
|
48
|
+
calculable_attrs_values[name] = value
|
49
|
+
end
|
50
|
+
|
51
|
+
def calculable_attrs_values
|
52
|
+
@calculable_attrs_values ||= {}
|
53
|
+
end
|
54
|
+
|
55
|
+
def calculable_attrs_values=(values)
|
56
|
+
values.each { |key, value| set_calculable_attr_value(key, value) }
|
57
|
+
end
|
58
|
+
|
59
|
+
def recalc_calculable_attr_with_siblings(name)
|
60
|
+
name = name.to_sym
|
61
|
+
check_calculable_attr_name!(name)
|
62
|
+
calculator = self.class.calculable_attrs_calculators[name]
|
63
|
+
self.calculable_attrs_values = calculator.calculate_all(id)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def calculable_attrs_calculated_flags
|
69
|
+
@calculable_attrs_calculated_flags ||= {}
|
70
|
+
end
|
71
|
+
|
72
|
+
def check_calculable_attr_name!(name)
|
73
|
+
unless self.class.calculable_attrs_calculators[name.to_sym]
|
74
|
+
raise "CALCULABLE_ATTRS: Unknown calculable attribute #{ name } for model #{ self.class.name }"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module CalculableAttrs::ActiveRecord::Relation
|
2
|
+
def calculate_attrs(*attrs)
|
3
|
+
spawn.calculate_attrs!(*attrs)
|
4
|
+
end
|
5
|
+
|
6
|
+
def calculate_attrs!(*attrs)
|
7
|
+
attrs.reject!(&:blank?)
|
8
|
+
attrs.flatten!
|
9
|
+
|
10
|
+
attrs = [true] if attrs.empty?
|
11
|
+
|
12
|
+
self.calculate_attrs_values |= attrs
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def calculate_attrs_values
|
17
|
+
@values[:calculate_attrs] || []
|
18
|
+
end
|
19
|
+
|
20
|
+
def calculate_attrs_values=(values)
|
21
|
+
raise ImmutableRelation if @loaded
|
22
|
+
@values[:calculate_attrs] = values
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def self.included(base)
|
27
|
+
base.class_eval do
|
28
|
+
alias_method :calculable_orig_exec_queries, :exec_queries
|
29
|
+
def exec_queries
|
30
|
+
calculable_orig_exec_queries
|
31
|
+
append_calculable_attrs
|
32
|
+
@records
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def append_calculable_attrs
|
40
|
+
unless calculate_attrs_values.empty?
|
41
|
+
models_calculable_scopes= {}
|
42
|
+
collect_models_calculable_attrs(models_calculable_scopes, klass, calculate_attrs_values)
|
43
|
+
models_calculable_scopes = models_calculable_scopes.select { |model, scope| scope.has_attrs }
|
44
|
+
collect_models_ids(models_calculable_scopes, @records, calculate_attrs_values)
|
45
|
+
models_calculable_scopes.each { |model, sope| sope.calculate }
|
46
|
+
put_calcaulated_values(models_calculable_scopes, @records, calculate_attrs_values)
|
47
|
+
end
|
48
|
+
|
49
|
+
@records
|
50
|
+
end
|
51
|
+
|
52
|
+
def collect_models_calculable_attrs(models_calculable_scopes, klass, attrs_to_calcualte)
|
53
|
+
attrs_to_calcualte = [attrs_to_calcualte] unless attrs_to_calcualte.is_a?(Array)
|
54
|
+
scope = (models_calculable_scopes[klass] ||= CalculableAttrs::ModelCalculableAttrsScope.new(klass))
|
55
|
+
attrs_to_calcualte.each do |attrs_to_calcualte_item|
|
56
|
+
|
57
|
+
case attrs_to_calcualte_item
|
58
|
+
when Symbol
|
59
|
+
if klass.reflect_on_association(attrs_to_calcualte_item)
|
60
|
+
collect_association_calculable_attrs(models_calculable_scopes, klass, attrs_to_calcualte_item, true)
|
61
|
+
else
|
62
|
+
scope.add_attr(attrs_to_calcualte_item)
|
63
|
+
end
|
64
|
+
when true
|
65
|
+
scope.add_all_attrs
|
66
|
+
when Hash
|
67
|
+
attrs_to_calcualte_item.each do |association_name, association_attrs_to_calcualte|
|
68
|
+
collect_association_calculable_attrs(models_calculable_scopes, klass, association_name, association_attrs_to_calcualte)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def collect_association_calculable_attrs(models_calculable_scopes, klass, assocaition_name, association_attrs_to_calcualte)
|
75
|
+
assocaition = klass.reflect_on_association(assocaition_name)
|
76
|
+
if assocaition
|
77
|
+
collect_models_calculable_attrs(models_calculable_scopes, assocaition.klass, association_attrs_to_calcualte)
|
78
|
+
else
|
79
|
+
p "CALCUALBLE_ATTRS: WAINING: Model #{ klass.name } does't have association attribute #{ assocaition_name }."
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def collect_models_ids(models_calculable_scopes, records, attrs_to_calculate)
|
84
|
+
itereate_scoped_records_recursively(models_calculable_scopes, records, attrs_to_calculate) do |scope, record|
|
85
|
+
scope.add_id(record.id)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def put_calcaulated_values(models_calculable_scopes, records, attrs_to_calculate)
|
91
|
+
itereate_scoped_records_recursively(models_calculable_scopes, records, attrs_to_calculate) do |scope, record|
|
92
|
+
record.calculable_attrs_values = scope.calcualted_attrs_values(record.id)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def itereate_scoped_records_recursively(models_calculable_scopes, records, attrs_to_calculate, &block)
|
97
|
+
itereate_records_recursively(records, attrs_to_calculate) do |record|
|
98
|
+
scope = models_calculable_scopes[record.class]
|
99
|
+
block.call(scope, record) if scope
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def itereate_records_recursively(records, attrs_to_calculate, &block)
|
104
|
+
attrs_to_calcualte = [attrs_to_calcualte] unless attrs_to_calcualte.is_a?(Array)
|
105
|
+
records = [records] unless records.is_a?(Array)
|
106
|
+
|
107
|
+
records.each do |record|
|
108
|
+
block.call(record)
|
109
|
+
|
110
|
+
attrs_to_calculate.select {|item| item.is_a?(Hash)}.each do |hash|
|
111
|
+
hash.each do |assocaition_name, assocaition_attributes|
|
112
|
+
if record.respond_to?(assocaition_name)
|
113
|
+
associated_records = record.send(assocaition_name)
|
114
|
+
associated_records = associated_records.respond_to?(:to_a) ? associated_records.to_a : associated_records
|
115
|
+
itereate_records_recursively(associated_records, attrs_to_calculate, &block)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
class CalculableAttrs::Calculator
|
2
|
+
CALCULABLE_FOREIGN_KEY = '__calculable_id__'
|
3
|
+
attr_reader :attrs
|
4
|
+
|
5
|
+
def initialize(relation: nil, foreign_key: nil, attributes: nil)
|
6
|
+
@relation = relation
|
7
|
+
@foreign_key = foreign_key
|
8
|
+
|
9
|
+
@attrs = []
|
10
|
+
@formulas = {}
|
11
|
+
@defaults = {}
|
12
|
+
|
13
|
+
attributes.each do |key, val|
|
14
|
+
key = key.to_sym
|
15
|
+
save_attribute_value(key, val)
|
16
|
+
@attrs << key
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def calculate(attrs, id)
|
21
|
+
if(id.is_a?(Array))
|
22
|
+
calculate_many(attrs, id)
|
23
|
+
else
|
24
|
+
calculate_one(attrs, id)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def calculate_many(attrs, ids)
|
29
|
+
query = base_query(attrs, ids).select("#{ @foreign_key } AS #{ CALCULABLE_FOREIGN_KEY }").group(@foreign_key)
|
30
|
+
records = query.load
|
31
|
+
noramlize_many_records_result(ids, attrs, records)
|
32
|
+
end
|
33
|
+
|
34
|
+
def calculate_one(attrs, id)
|
35
|
+
record = base_query(attrs, id).load.first
|
36
|
+
noramlize_one_record_result(attrs, record)
|
37
|
+
end
|
38
|
+
|
39
|
+
def calculate_all(id)
|
40
|
+
calculate(attrs, id)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def save_attribute_value(name, value)
|
46
|
+
case value
|
47
|
+
when String
|
48
|
+
@formulas[name] = value
|
49
|
+
when Array
|
50
|
+
if value.size == 2
|
51
|
+
@formulas[name] = value[0]
|
52
|
+
@defaults[name] = value[1]
|
53
|
+
else
|
54
|
+
raise "CALCUALBEL_ATTRS: Invalid attribute array for #{ name }. Expected ['formula', default_value]"
|
55
|
+
end
|
56
|
+
else
|
57
|
+
raise "CALCUALBEL_ATTRS: Invalid attribute value for #{ name }"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def base_query(attrs, id)
|
62
|
+
@relation.call.select(build_select(attrs)).where( @foreign_key => id)
|
63
|
+
end
|
64
|
+
|
65
|
+
def noramlize_many_records_result(ids, attrs, records)
|
66
|
+
normalized = {}
|
67
|
+
records.each do |row|
|
68
|
+
id = row[CALCULABLE_FOREIGN_KEY].to_i
|
69
|
+
normalized[id] = noramlize_one_record_result(attrs, row)
|
70
|
+
end
|
71
|
+
ids.each do |id|
|
72
|
+
normalized[id] ||= noramlize_one_record_result(attrs, nil)
|
73
|
+
end
|
74
|
+
normalized
|
75
|
+
end
|
76
|
+
|
77
|
+
def noramlize_one_record_result(attrs, record)
|
78
|
+
attrs.map { |a| [a, record.try(a) || ( @defaults.key?(a) ? @defaults[a] : 0)] }.to_h
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
def build_select(attrs)
|
83
|
+
attrs.map { |a| "#{ @formulas[a] } AS #{ a }" }.join(', ')
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class CalculableAttrs::ModelCalculableAttrsScope
|
2
|
+
attr_reader :model, :ids, :attrs
|
3
|
+
|
4
|
+
def initialize(model)
|
5
|
+
@model = model
|
6
|
+
@attrs = []
|
7
|
+
@ids = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_attr(attrribute)
|
11
|
+
attrribute = attrribute.to_sym
|
12
|
+
@attrs.push(attrribute) unless @attrs.include?(attrribute)
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_all_attrs
|
16
|
+
@attrs = model.calculable_attrs
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_attrs
|
20
|
+
@attrs.size > 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_id(id)
|
24
|
+
@ids.push(id.to_i)
|
25
|
+
end
|
26
|
+
|
27
|
+
def calculate
|
28
|
+
@calculable_attrs_values = nil
|
29
|
+
calculators_to_use.each do |calulator|
|
30
|
+
calcualted_values = calulator.calculate_many(attrs | @attrs, ids)
|
31
|
+
merge_calculated_values(calcualted_values)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def calcualted_attrs_values(id)
|
36
|
+
@calculable_attrs_values[id.to_i]
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def merge_calculated_values(calcualted_values)
|
43
|
+
if @calculable_attrs_values
|
44
|
+
calcualted_values.each {|id,values| @calculable_attrs_values[id].merge!(calcualted_values[id]) }
|
45
|
+
else
|
46
|
+
@calculable_attrs_values = calcualted_values
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def calculators_to_use
|
51
|
+
calculators_to_use = []
|
52
|
+
@attrs.each do |attribute|
|
53
|
+
calulator = @model.calculable_attrs_calculators[attribute]
|
54
|
+
calculators_to_use.push(calulator) unless calculators_to_use.include?(calulator)
|
55
|
+
end
|
56
|
+
calculators_to_use
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Calculable; end
|
2
|
+
|
3
|
+
require 'calculable_attrs/active_record'
|
4
|
+
require 'calculable_attrs/calculator'
|
5
|
+
require 'calculable_attrs/model_calculable_attrs_scope'
|
6
|
+
|
7
|
+
::ActiveRecord::Base.include(CalculableAttrs::ActiveRecord::Base)
|
8
|
+
::ActiveRecord::Relation.include(CalculableAttrs::ActiveRecord::Relation)
|
9
|
+
::ActiveRecord::Base.extend(CalculableAttrs::ActiveRecord::Querying)
|
metadata
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: calculable_attrs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dmitry Sharkov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sqlite3
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec-rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: factory_girl_rails
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: database_cleaner
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: |2
|
84
|
+
Imagine you an Account model which has many transactions.
|
85
|
+
calculable_attrs gem allows you to define Accoutn#blalace and SUM(transactions.amount) directrly in your Account model.
|
86
|
+
And solves n+1 problem for you in an elegant way.
|
87
|
+
email:
|
88
|
+
- dmitry.sharkov@gmail.com
|
89
|
+
executables: []
|
90
|
+
extensions: []
|
91
|
+
extra_rdoc_files: []
|
92
|
+
files:
|
93
|
+
- MIT-LICENSE
|
94
|
+
- Rakefile
|
95
|
+
- lib/calculable_attrs.rb
|
96
|
+
- lib/calculable_attrs/active_record.rb
|
97
|
+
- lib/calculable_attrs/active_record/base.rb
|
98
|
+
- lib/calculable_attrs/active_record/querying.rb
|
99
|
+
- lib/calculable_attrs/active_record/relation.rb
|
100
|
+
- lib/calculable_attrs/calculator.rb
|
101
|
+
- lib/calculable_attrs/model_calculable_attrs_scope.rb
|
102
|
+
- lib/calculable_attrs/version.rb
|
103
|
+
- lib/tasks/calculable_tasks.rake
|
104
|
+
homepage: https://github.com/dmitrysharkov/calculable_attrs
|
105
|
+
licenses:
|
106
|
+
- MIT
|
107
|
+
metadata: {}
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
requirements: []
|
123
|
+
rubyforge_project:
|
124
|
+
rubygems_version: 2.2.2
|
125
|
+
signing_key:
|
126
|
+
specification_version: 4
|
127
|
+
summary: Simplifies work with dynamically calculable fields.
|
128
|
+
test_files: []
|