dase 3.2.7 → 3.2.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0caefe9687496a603d4b8a1812f0a3a89320bc58
4
+ data.tar.gz: fe0dd23b22c989fefade0b8cd4555925083c19a3
5
+ SHA512:
6
+ metadata.gz: 7cd235f4fa1de0ee5ea6c4c36cbe73beeb295d3665aa1532e4ac2740ab42c9008770c3627a3df30ab17535743ce4d6e77737f5df1a04b19ed4e6cdc51847d67b
7
+ data.tar.gz: 02d35d30617d7805da0ebc6f9b894b31594bf40c2a0af2622ce672f20e6c0eff410052ef621abdf25dde3d10f12dc366b0253cd293fc6432a59af51fe635f3bc
data/README.md CHANGED
@@ -103,3 +103,7 @@ who was a mental calculator - he could count and multiply numbers very quickly.
103
103
  3. Commit your changes (`git commit -am 'Add some feature'`)
104
104
  4. Push to the branch (`git push origin my-new-feature`)
105
105
  5. Create new Pull Request
106
+
107
+
108
+ [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/vovayartsev/dase/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
109
+
data/dase.gemspec CHANGED
@@ -7,6 +7,7 @@ Gem::Specification.new do |gem|
7
7
  gem.name = "dase"
8
8
  gem.version = Dase::VERSION
9
9
  gem.authors = ["Vladimir Yartsev"]
10
+ gem.licenses = ["MIT"]
10
11
  gem.email = ["vovayartsev@gmail.com"]
11
12
  gem.description = %q{Dase gem creates includes_count_of method in ActiveRecord::Relation
12
13
  to count associated records efficiently. See examples at https://github.com/vovayartsev/dase
@@ -24,7 +25,7 @@ Gem::Specification.new do |gem|
24
25
  gem.add_development_dependency 'sqlite3', '~> 1.3.3'
25
26
  end
26
27
 
27
- # gem.add_development_dependency 'debugger'
28
+ # gem.add_development_dependency 'pry'
28
29
  gem.add_development_dependency 'rake'
29
30
  gem.add_development_dependency 'rspec-core'
30
31
 
@@ -0,0 +1,59 @@
1
+ module Dase
2
+ module ARRelationInstanceMethods
3
+ def dase_values
4
+ @dase_values ||= {}
5
+ end
6
+
7
+ def includes_count_of(*args)
8
+ options = args.extract_options!
9
+ sanitize_includes_count_of_options(args, options)
10
+ return self if args.empty?
11
+ clone.tap do |relation|
12
+ args.each do |arg|
13
+ counter_name = (options[:as] || "#{arg}_count").to_sym
14
+ relation.dase_values[counter_name] = options.merge(as: counter_name, association: arg.to_sym)
15
+ end
16
+ end
17
+ end
18
+
19
+ def merge(other)
20
+ super(other).tap do |result|
21
+ result.dase_values.merge!(other.dase_values || {}) if other # other == nil is fine too
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def sanitize_includes_count_of_options(args, options)
28
+ options.assert_valid_keys(:proc, :as, :only, :conditions, :group, :having, :limit, :offset, :joins, :include, :from, :lock)
29
+ if options.present? and args.many?
30
+ raise ArgumentError, 'includes_count_of takes either multiple associations OR single association + options'
31
+ end
32
+ end
33
+
34
+ def attach_dase_counters_to_records
35
+ (dase_values || {}).each do |_, options|
36
+ Dase::Preloader.new(@records, options[:association], options).run
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ ActiveRecord::Relation.class_eval do
43
+ include Dase::ARRelationInstanceMethods
44
+
45
+ private
46
+
47
+ # why overwriting with include/extend doesn't work???
48
+ alias_method :exec_queries_before_dase, :exec_queries
49
+
50
+ def exec_queries
51
+ after_hook = loaded? ? proc {} : proc { attach_dase_counters_to_records }
52
+ exec_queries_before_dase.tap(&after_hook)
53
+ end
54
+ end
55
+
56
+ class << ActiveRecord::Base
57
+ delegate :includes_count_of, :to => :scoped
58
+ end
59
+
@@ -2,14 +2,16 @@ module Dase
2
2
  class Preloader < ::ActiveRecord::Associations::Preloader
3
3
 
4
4
  # custom preloaders for different association types
5
+
5
6
  class HasMany < ::ActiveRecord::Associations::Preloader::HasMany
6
7
  include Dase::PreloaderMethods
7
8
  end
9
+
8
10
  class HasAndBelongsToMany < ::ActiveRecord::Associations::Preloader::HasAndBelongsToMany
9
11
  include Dase::PreloaderMethods
10
12
  end
11
13
 
12
- # Not implemented yet
14
+ # Not fully implemented yet
13
15
  class HasManyThrough < ::ActiveRecord::Associations::Preloader::HasManyThrough
14
16
  include Dase::PreloaderMethods
15
17
 
@@ -2,12 +2,9 @@ module Dase
2
2
  module PreloaderMethods
3
3
 
4
4
  def initialize(klass, owners, reflection, preload_options)
5
- # grabbing our options
6
- preload_options = preload_options.clone
7
- @dase_association = preload_options.delete(:association)
5
+ preload_options = preload_options.reject { |k, _| k == :association }
8
6
  @dase_counter_name = preload_options.delete(:as)
9
7
  @dase_scope_to_merge = preload_options.delete(:only)
10
- #@dase_proc = preload_options.delete(:proc)
11
8
  super(klass, owners, reflection, preload_options)
12
9
  end
13
10
 
@@ -20,20 +17,11 @@ module Dase
20
17
  ids = owners.map(&pk)
21
18
  scope = records_for(ids)
22
19
  scope = scope.merge(@dase_scope_to_merge) if @dase_scope_to_merge
23
- #if @dase_proc # support for includes_count_of(...){ where(...) } syntax
24
- # case @dase_proc.arity
25
- # when 0
26
- # scope = scope.instance_eval &@dase_proc
27
- # when 1
28
- # scope = @dase_proc.call(scope)
29
- # else
30
- # raise ArgumentError, "The block passed to includes_count_of takes 0 or 1 arguments"
31
- # end
32
- #end
33
- counters_hash = scope.count(:group => prefixed_foreign_key)
20
+ counters_hash = scope.count(group: prefixed_foreign_key)
34
21
  owners.each do |owner|
35
- value = counters_hash[owner[pk]] || 0 # 0 is "default count", when no records found
36
- owner.set_dase_counter(@dase_counter_name, value)
22
+ owner.define_singleton_method(@dase_counter_name) do
23
+ counters_hash[owner[pk]] || 0
24
+ end
37
25
  end
38
26
  end
39
27
 
data/lib/dase/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Dase
2
- VERSION = "3.2.7"
2
+ VERSION = '3.2.9'
3
3
  end
data/lib/dase.rb CHANGED
@@ -1,10 +1,9 @@
1
1
  require "dase/version"
2
2
  require "dase/preloader_methods"
3
3
  require "dase/preloader"
4
- require "dase/mp_active_record_base"
5
- require "dase/mp_active_record_relation"
4
+ require "dase/mp_active_record"
6
5
 
7
6
  module Dase
8
- # take a look at mp_active_record_* files
7
+ # take a look at mp_active_record files
9
8
  # (there we monkey-patch Active Record)
10
9
  end
data/test/test_dase.rb CHANGED
@@ -68,20 +68,7 @@ class TestBase < Test::Unit::TestCase
68
68
  assert_equal 3, Author.includes_count_of(:books).merge(nil).all.size
69
69
  end
70
70
 
71
- #should "count using block conditions (arity: 0)" do
72
- # dase_counts = Author.includes_count_of(:books){where(:year => 2012)}.order(:name).map { |a| a.books_count }
73
- # # the order is: Bobby, Joe, Teddy - due to order(:name)
74
- # true_counts = [0, 1, 0] # see books.yml
75
- # assert_equal true_counts, dase_counts, "results mismatch"
76
- #end
77
- #
78
- #should "count using block conditions (arity: 1)" do
79
- # @y = 2012
80
- # dase_counts = Author.includes_count_of(:books){ |books| books.where(:year => @y)}.order(:name).map { |a| a.books_count }
81
- # # the order is: Bobby, Joe, Teddy - due to order(:name)
82
- # true_counts = [0, 1, 0] # see books.yml
83
- # assert_equal true_counts, dase_counts, "results mismatch"
84
- #end
71
+ # pending "apply: lambda {where...}"
85
72
 
86
73
  should "count likes" do
87
74
  dase_counts = Author.order(:name).includes_count_of(:scores).map { |a| a.scores_count }
@@ -103,6 +90,15 @@ class TestBase < Test::Unit::TestCase
103
90
  assert_equal 3, joe.books_count, "Invalid books_count"
104
91
  assert_equal 2, joe.old_books_count, "Invalid old_books_count"
105
92
  end
93
+ end
106
94
 
95
+ context 'test' do
96
+ should 'work with find_each' do
97
+ # the order is: Bobby, Joe, Teddy - due to sort_by(:name)
98
+ records = []
99
+ Author.includes_count_of(:books).find_each(batch_size: 2) { |r| records << r }
100
+ dase_count = records.sort_by(&:name).map { |a| a.books_count }
101
+ assert_equal [1, 3, 0], dase_count, "dase countings failed" # see books.yml
102
+ end
107
103
  end
108
104
  end
metadata CHANGED
@@ -1,103 +1,117 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: dase
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 3.2.7
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.2.9
6
5
  platform: ruby
7
- authors:
6
+ authors:
8
7
  - Vladimir Yartsev
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
-
13
- date: 2013-03-01 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
11
+ date: 2014-08-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
16
14
  name: activesupport
17
- prerelease: false
18
- requirement: &id001 !ruby/object:Gem::Requirement
19
- none: false
20
- requirements:
21
- - - ~>
22
- - !ruby/object:Gem::Version
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
23
19
  version: 3.2.0
24
20
  type: :runtime
25
- version_requirements: *id001
26
- - !ruby/object:Gem::Dependency
27
- name: shoulda
28
21
  prerelease: false
29
- requirement: &id002 !ruby/object:Gem::Requirement
30
- none: false
31
- requirements:
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 3.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: shoulda
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
32
31
  - - ">="
33
- - !ruby/object:Gem::Version
34
- version: "0"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
35
34
  type: :development
36
- version_requirements: *id002
37
- - !ruby/object:Gem::Dependency
38
- name: activerecord
39
35
  prerelease: false
40
- requirement: &id003 !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ~>
44
- - !ruby/object:Gem::Version
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: activerecord
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
45
47
  version: 3.2.0
46
48
  type: :runtime
47
- version_requirements: *id003
48
- - !ruby/object:Gem::Dependency
49
- name: sqlite3
50
49
  prerelease: false
51
- requirement: &id004 !ruby/object:Gem::Requirement
52
- none: false
53
- requirements:
54
- - - ~>
55
- - !ruby/object:Gem::Version
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.2.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: sqlite3
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
56
61
  version: 1.3.3
57
62
  type: :development
58
- version_requirements: *id004
59
- - !ruby/object:Gem::Dependency
60
- name: rake
61
63
  prerelease: false
62
- requirement: &id005 !ruby/object:Gem::Requirement
63
- none: false
64
- requirements:
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 1.3.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
65
73
  - - ">="
66
- - !ruby/object:Gem::Version
67
- version: "0"
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
68
76
  type: :development
69
- version_requirements: *id005
70
- - !ruby/object:Gem::Dependency
71
- name: rspec-core
72
77
  prerelease: false
73
- requirement: &id006 !ruby/object:Gem::Requirement
74
- none: false
75
- requirements:
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
76
80
  - - ">="
77
- - !ruby/object:Gem::Version
78
- version: "0"
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec-core
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
79
90
  type: :development
80
- version_requirements: *id006
81
- description: "Dase gem creates includes_count_of method in ActiveRecord::Relation\n to count associated records efficiently. See examples at https://github.com/vovayartsev/dase\n "
82
- email:
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: "Dase gem creates includes_count_of method in ActiveRecord::Relation\n
98
+ \ to count associated records efficiently. See examples at
99
+ https://github.com/vovayartsev/dase\n "
100
+ email:
83
101
  - vovayartsev@gmail.com
84
102
  executables: []
85
-
86
103
  extensions: []
87
-
88
104
  extra_rdoc_files: []
89
-
90
- files:
91
- - .gitignore
92
- - .travis.yml
105
+ files:
106
+ - ".gitignore"
107
+ - ".travis.yml"
93
108
  - Gemfile
94
109
  - LICENSE.txt
95
110
  - README.md
96
111
  - Rakefile
97
112
  - dase.gemspec
98
113
  - lib/dase.rb
99
- - lib/dase/mp_active_record_base.rb
100
- - lib/dase/mp_active_record_relation.rb
114
+ - lib/dase/mp_active_record.rb
101
115
  - lib/dase/preloader.rb
102
116
  - lib/dase/preloader_methods.rb
103
117
  - lib/dase/version.rb
@@ -113,33 +127,31 @@ files:
113
127
  - test/helper.rb
114
128
  - test/test_dase.rb
115
129
  homepage: https://github.com/vovayartsev/dase
116
- licenses: []
117
-
130
+ licenses:
131
+ - MIT
132
+ metadata: {}
118
133
  post_install_message:
119
134
  rdoc_options: []
120
-
121
- require_paths:
135
+ require_paths:
122
136
  - lib
123
- required_ruby_version: !ruby/object:Gem::Requirement
124
- none: false
125
- requirements:
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
126
139
  - - ">="
127
- - !ruby/object:Gem::Version
128
- version: "0"
129
- required_rubygems_version: !ruby/object:Gem::Requirement
130
- none: false
131
- requirements:
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
132
144
  - - ">="
133
- - !ruby/object:Gem::Version
134
- version: "0"
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
135
147
  requirements: []
136
-
137
148
  rubyforge_project:
138
- rubygems_version: 1.8.23
149
+ rubygems_version: 2.2.2
139
150
  signing_key:
140
- specification_version: 3
141
- summary: Provides includes_count_of method on ActiveRecord::Relation to count associated records efficiently
142
- test_files:
151
+ specification_version: 4
152
+ summary: Provides includes_count_of method on ActiveRecord::Relation to count associated
153
+ records efficiently
154
+ test_files:
143
155
  - test/fixtures/author.rb
144
156
  - test/fixtures/authors.yml
145
157
  - test/fixtures/book.rb
@@ -1,47 +0,0 @@
1
- # Monkey-patching ActiveRecord::Base to add xxx_count methods to it
2
-
3
- module Dase
4
- module ARBaseInstanceMethods
5
- def set_dase_counter(name, value)
6
- @dase_counters ||= {}
7
- @dase_counters[name.to_sym] = value
8
- end
9
-
10
- def get_dase_counter(name)
11
- @dase_counters[name]
12
- end
13
-
14
- def respond_to?(*args)
15
- @dase_counters && @dase_counters.has_key?(args.first.to_sym) || super
16
- end
17
-
18
- def method_missing(name, *args)
19
- if @dase_counters and @dase_counters.has_key?(name.to_sym)
20
- get_dase_counter(name, *args)
21
- else
22
- super
23
- end
24
- end
25
-
26
- # This method uses traditions counting method
27
- # and stores the results in dase-compatible form
28
- def refresh_dase_counters!(*associations)
29
- associations.flatten.each do |assoc|
30
- value = self.send(assoc).count # i.e. book.quotes.count
31
- set_dase_counter "#{column}_count", value # i.e. book.quotes_count = value
32
- end
33
- end
34
-
35
- private
36
-
37
- def self.included(klass)
38
- class << klass
39
- delegate :includes_count_of, :to => :scoped
40
- end
41
- end
42
- end
43
- end
44
-
45
- ActiveRecord::Base.class_eval do
46
- include Dase::ARBaseInstanceMethods
47
- end
@@ -1,59 +0,0 @@
1
- module Dase
2
- module ARRelationInstanceMethods
3
- attr_accessor :dase_values
4
-
5
- def includes_count_of(*args)
6
- args.reject! { |a| a.blank? }
7
- options = args.extract_options!
8
- options.assert_valid_keys(:proc, :as, :only, :conditions, :group, :having, :limit, :offset, :joins, :include, :from, :lock)
9
- return self if args.empty?
10
- if options.present? and args.many?
11
- raise ArgumentError, "includes_count_of takes either multiple associations OR single association + options"
12
- end
13
- relation = clone
14
- relation.dase_values ||= {}
15
- #options[:proc] = block if block
16
- args.each do |arg|
17
- opts = options.clone
18
- opts[:association] = arg.to_sym
19
- opts[:as] = (opts[:as] || "#{arg}_count").to_sym
20
- relation.dase_values[opts[:as]] = opts
21
- end
22
- relation
23
- end
24
-
25
- def attach_dase_counters_to_records
26
- if dase_values.present? and !@has_dase_counters
27
- dase_values.each do |name, options|
28
- Dase::Preloader.new(@records, options[:association], options).run
29
- end
30
- @has_dase_counters = true
31
- end
32
- end
33
-
34
- def merge(r)
35
- super(r).tap do |result|
36
- # it's ok to get nil here - ActiveRecord works fine in that case
37
- if !r.nil? and r.dase_values.present?
38
- result.dase_values ||= {}
39
- result.dase_values.merge!(r.dase_values)
40
- end
41
- end
42
- end
43
- end
44
- end
45
-
46
-
47
- ActiveRecord::Relation.class_eval do
48
- include Dase::ARRelationInstanceMethods
49
-
50
- private
51
-
52
- alias_method :exec_queries_before_dase, :exec_queries
53
-
54
- def exec_queries
55
- exec_queries_before_dase # original method from ActiveRecord
56
- attach_dase_counters_to_records
57
- @records
58
- end
59
- end