dase 3.2.7 → 3.2.9

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 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