calculated_attributes 0.1.3 → 0.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 114648311fe5389527380b81d89677279f8e9019
4
- data.tar.gz: 42e5dc334c01643eaf56d97e4eb42aca0cb0113d
3
+ metadata.gz: 31b050a3311b7b6c70f23b201f4761b103b6137f
4
+ data.tar.gz: 875255b28e9c8e597b4bf0d912f3f02283544d18
5
5
  SHA512:
6
- metadata.gz: 6635d62772fca4d1da02752555ed19fd55c8b04d9047e95086c233f89ee83822c7e277257ba21607e9bf7bf484b518e2547477333f5da84a1ccd0bcea223cc7d
7
- data.tar.gz: f5881cb7665e8132f22ee7dbfd932b7695d420cd5fec33fb7e2248a40cdd2975ca093a37fca39ff0375e493e1039fef630c06213935eefa771a13392ebe16772
6
+ metadata.gz: 9dd904985c4d11aa47ecbc53e90b9500f5a427437ec934e8666ffdb29db88c129151843899f93dad9dc6f9aa884903933ad529b0f5bf03c8e15ad5a23e718f18
7
+ data.tar.gz: 493f1937397278a71be5743c39160f12582ebe30a93530de9e9138454423e475259fc72e0d1c26d800314a4a5b39f7d956443855827bd014c9a05bc2658c54c2
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
- [![Gem Version](https://badge.fury.io/rb/calculated_attributes.svg)](https://badge.fury.io/rb/calculated_attributes)
1
+ [![Gem Version](https://badge.fury.io/rb/calculated_attributes.svg)](https://badge.fury.io/rb/calculated_attributes)
2
+ [![CircleCI](https://circleci.com/gh/aha-app/calculated_attributes.svg?style=shield)](https://circleci.com/gh/aha-app/calculated_attributes)
2
3
 
3
4
  # CalculatedAttributes
4
5
 
@@ -22,7 +23,7 @@ Or install it yourself as:
22
23
 
23
24
  ## Usage
24
25
 
25
- Add each calculated attribute to your model using the `calculated` keyword. It accepts two parameters: a symbol representing the name of the calculated attribute, and a lambda containing a string to calculate the attribute.
26
+ Add each calculated attribute to your model using the `calculated` keyword. It accepts two parameters: a symbol representing the name of the calculated attribute, and a lambda containing a string to calculate the attribute. The lambda can accept arguments.
26
27
 
27
28
  For example, if we have two models, `Post` and `Comment`, and `Comment` has a `post_id` attribute, we might write the following code to add a comments count to each `Post` record in a relation:
28
29
 
@@ -30,6 +31,7 @@ For example, if we have two models, `Post` and `Comment`, and `Comment` has a `p
30
31
  class Post < ActiveRecord::Base
31
32
  ...
32
33
  calculated :comments_count, -> { "select count(*) from comments where comments.post_id = posts.id" }
34
+ calculated :comments_count_by_user, ->(user) { ["select count(*) from comments where comments.post_id = posts.id and posts.user_id = '%s'", user.id] }
33
35
  ...
34
36
  end
35
37
  ```
@@ -38,6 +40,7 @@ Then, the comments count may be accessed as follows:
38
40
 
39
41
  ```ruby
40
42
  Post.scoped.calculated(:comments_count).first.comments_count
43
+ Post.scoped.calculated(comments_count_by_user: user).first.comments_count_by_user
41
44
  #=> 5
42
45
  ```
43
46
 
@@ -69,6 +72,9 @@ You may also use the `calculated` method on a single model instance, like so:
69
72
  ```ruby
70
73
  Post.first.calculated(:comments_count).comments_count
71
74
  #=> 5
75
+
76
+ Post.first.calculated(comments_count_by_user: user).comments_count_by_user
77
+ #=> 0
72
78
  ```
73
79
 
74
80
  If you have defined a `calculated` method, results of that method will be returned rather than throwing a method missing error even if you don't explicitly use the `calculated()` call on the instance:
@@ -76,6 +82,8 @@ If you have defined a `calculated` method, results of that method will be return
76
82
  ```ruby
77
83
  Post.first.comments_count
78
84
  #=> 5
85
+ Post.first.comments_count_by_user(user)
86
+ #=> 0
79
87
  ```
80
88
 
81
89
  If you like, you may define `calculated` lambdas using Arel syntax:
@@ -108,4 +116,4 @@ will error. This is because of an [ActiveRecord issue](https://github.com/rails/
108
116
 
109
117
  ## Credits
110
118
 
111
- Written by Zach Schneider based on ideas from Chris Waters.
119
+ Written by Zach Schneider based on ideas from Chris Waters.
@@ -18,7 +18,6 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ['lib']
19
19
 
20
20
  spec.add_development_dependency 'appraisal', '~> 1.0.3'
21
- spec.add_development_dependency 'bundler', '~> 1.7'
22
21
  spec.add_development_dependency 'rake', '~> 10.0'
23
22
  spec.add_development_dependency 'rspec', '~> 3.1'
24
23
  spec.add_development_dependency 'rubocop', '~> 0.32.0'
data/circle.yml ADDED
@@ -0,0 +1,3 @@
1
+ database:
2
+ override:
3
+ - echo "no database setup"
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../
3
3
  specs:
4
- calculated_attributes (0.1.2)
4
+ calculated_attributes (0.1.4)
5
5
  activerecord (>= 3.2.20)
6
6
 
7
7
  GEM
@@ -27,7 +27,6 @@ GEM
27
27
  astrolabe (1.3.0)
28
28
  parser (>= 2.2.0.pre.3, < 3.0)
29
29
  builder (3.0.4)
30
- byebug (6.0.2)
31
30
  diff-lcs (1.2.5)
32
31
  i18n (0.7.0)
33
32
  multi_json (1.11.1)
@@ -66,10 +65,11 @@ PLATFORMS
66
65
  DEPENDENCIES
67
66
  activerecord (= 3.2.21)
68
67
  appraisal (~> 1.0.3)
69
- bundler (~> 1.7)
70
- byebug
71
68
  calculated_attributes!
72
69
  rake (~> 10.0)
73
70
  rspec (~> 3.1)
74
71
  rubocop (~> 0.32.0)
75
72
  sqlite3 (~> 1.3.10)
73
+
74
+ BUNDLED WITH
75
+ 1.11.2
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../
3
3
  specs:
4
- calculated_attributes (0.1.2)
4
+ calculated_attributes (0.1.4)
5
5
  activerecord (>= 3.2.20)
6
6
 
7
7
  GEM
@@ -29,7 +29,6 @@ GEM
29
29
  astrolabe (1.3.0)
30
30
  parser (>= 2.2.0.pre.3, < 3.0)
31
31
  builder (3.2.2)
32
- byebug (6.0.2)
33
32
  diff-lcs (1.2.5)
34
33
  i18n (0.7.0)
35
34
  json (1.8.3)
@@ -71,10 +70,11 @@ PLATFORMS
71
70
  DEPENDENCIES
72
71
  activerecord (= 4.1.11)
73
72
  appraisal (~> 1.0.3)
74
- bundler (~> 1.7)
75
- byebug
76
73
  calculated_attributes!
77
74
  rake (~> 10.0)
78
75
  rspec (~> 3.1)
79
76
  rubocop (~> 0.32.0)
80
77
  sqlite3 (~> 1.3.10)
78
+
79
+ BUNDLED WITH
80
+ 1.11.2
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../
3
3
  specs:
4
- calculated_attributes (0.1.2)
4
+ calculated_attributes (0.1.4)
5
5
  activerecord (>= 3.2.20)
6
6
 
7
7
  GEM
@@ -29,7 +29,6 @@ GEM
29
29
  astrolabe (1.3.0)
30
30
  parser (>= 2.2.0.pre.3, < 3.0)
31
31
  builder (3.2.2)
32
- byebug (6.0.2)
33
32
  diff-lcs (1.2.5)
34
33
  i18n (0.7.0)
35
34
  json (1.8.3)
@@ -71,10 +70,11 @@ PLATFORMS
71
70
  DEPENDENCIES
72
71
  activerecord (= 4.2.2)
73
72
  appraisal (~> 1.0.3)
74
- bundler (~> 1.7)
75
- byebug
76
73
  calculated_attributes!
77
74
  rake (~> 10.0)
78
75
  rspec (~> 3.1)
79
76
  rubocop (~> 0.32.0)
80
77
  sqlite3 (~> 1.3.10)
78
+
79
+ BUNDLED WITH
80
+ 1.11.2
@@ -42,9 +42,9 @@ class ActiveRecord::Base
42
42
  self.class.base_class
43
43
  end
44
44
  if class_with_attr.respond_to? :scoped
45
- class_with_attr.scoped.calculated(sym).find(id).send(sym)
45
+ class_with_attr.scoped.calculated(sym => args).find(id).send(sym)
46
46
  else
47
- class_with_attr.all.calculated(sym).find(id).send(sym)
47
+ class_with_attr.all.calculated(sym => args).find(id).send(sym)
48
48
  end
49
49
  else
50
50
  super(sym, *args, &block)
@@ -67,16 +67,24 @@ end
67
67
  class ActiveRecord::Relation
68
68
  def calculated(*args)
69
69
  projections = arel.projections
70
- args.each do |arg|
71
- lam = klass.calculated.calculated[arg] || klass.base_class.calculated.calculated[arg]
72
- sql = lam.call
70
+ args = args.flat_map do |arg|
71
+ case arg
72
+ when Symbol then [[arg, []]]
73
+ when Hash then arg.to_a
74
+ end
75
+ end
76
+
77
+ args.each do |attribute, arguments|
78
+ lam = klass.calculated.calculated[attribute] || klass.base_class.calculated.calculated[attribute]
79
+ sql = lam.call(*arguments)
80
+ sql = klass.send(:sanitize_sql, *sql) if sql.is_a?(Array)
73
81
  new_projection =
74
82
  if sql.is_a?(String)
75
- Arel.sql("(#{sql})").as(arg.to_s)
83
+ Arel.sql("(#{sql})").as(attribute.to_s)
76
84
  elsif sql.respond_to? :to_sql
77
- Arel.sql("(#{sql.to_sql})").as(arg.to_s)
85
+ Arel.sql("(#{sql.to_sql})").as(attribute.to_s)
78
86
  else
79
- sql.as(arg.to_s)
87
+ sql.as(attribute.to_s)
80
88
  end
81
89
  new_projection.calculated_attr!
82
90
  projections.push new_projection
@@ -1,3 +1,3 @@
1
1
  module CalculatedAttributes
2
- VERSION = '0.1.3'
2
+ VERSION = '0.1.4'
3
3
  end
@@ -13,6 +13,13 @@ describe 'calculated_attributes' do
13
13
  expect(model_scoped(Post).calculated(:comments_count).first.comments_count).to eq(1)
14
14
  end
15
15
 
16
+ it 'includes parametric calculated attributes' do
17
+ expect(model_scoped(Post).calculated(comments_by_user: [User.where(username: 'unused').first])
18
+ .first.comments_by_user).to eq(0)
19
+ expect(model_scoped(Post).calculated(comments_by_user: [User.where(username: 'test').first])
20
+ .first.comments_by_user).to eq(1)
21
+ end
22
+
16
23
  it 'includes multiple calculated attributes' do
17
24
  post = model_scoped(Post).calculated(:comments_count, :comments_two).first
18
25
  expect(post.comments_count).to eq(1)
@@ -37,10 +44,18 @@ describe 'calculated_attributes' do
37
44
  expect(Post.first.calculated(:comments_count).comments_count).to eq(1)
38
45
  end
39
46
 
47
+ it 'allows access via model instance method with parameters' do
48
+ expect(Post.first.calculated(comments_by_user: [User.where(username: 'test').first]).comments_by_user).to eq(1)
49
+ end
50
+
40
51
  it 'allows anonymous access via model instance method' do
41
52
  expect(Post.first.comments_count).to eq(1)
42
53
  end
43
54
 
55
+ it 'allows access via model instance method with parameters' do
56
+ expect(Post.first.comments_by_user(User.where(username: 'test').first)).to eq(1)
57
+ end
58
+
44
59
  it 'allows anonymous access via model instance method with STI and lambda on base class' do
45
60
  expect(Tutorial.first.comments_count).to eq(1)
46
61
  end
data/spec/support/data.rb CHANGED
@@ -1,5 +1,7 @@
1
- p = Post.create(text: 'First post!')
2
- Comment.create(post_id: p.id, text: 'First comment!')
1
+ u = User.create(username: 'test')
2
+ User.create(username: 'unused')
3
+ p = Post.create(text: 'First post!', user: u)
4
+ Comment.create(post_id: p.id, text: 'First comment!', user: u)
3
5
  Post.create(text: 'Second post!')
4
6
  t = Tutorial.create(text: 'Tutorial!')
5
7
  Comment.create(post_id: t.id, text: 'First comment!')
@@ -2,6 +2,7 @@ class Post < ActiveRecord::Base
2
2
  has_many :comments
3
3
  belongs_to :user
4
4
 
5
+ calculated :comments_by_user, ->(user) { "select count(*) from comments where comments.post_id = posts.id and comments.user_id = #{user.id}" }
5
6
  calculated :comments_count, -> { 'select count(*) from comments where comments.post_id = posts.id' }
6
7
  calculated :comments_two, -> { 'select count(*) from comments where comments.post_id = posts.id' }
7
8
  calculated :comments_arel, -> { Comment.where(Comment.arel_table[:post_id].eq(Post.arel_table[:id])).select(Arel.sql('count(*)')) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: calculated_attributes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Schneider
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-01 00:00:00.000000000 Z
11
+ date: 2016-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appraisal
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.0.3
27
- - !ruby/object:Gem::Dependency
28
- name: bundler
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '1.7'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '1.7'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: rake
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -118,12 +104,14 @@ files:
118
104
  - ".gitignore"
119
105
  - ".rspec"
120
106
  - ".rubocop.yml"
107
+ - ".ruby-version"
121
108
  - Appraisals
122
109
  - Gemfile
123
110
  - LICENSE.txt
124
111
  - README.md
125
112
  - Rakefile
126
113
  - calculated_attributes.gemspec
114
+ - circle.yml
127
115
  - gemfiles/rails3.gemfile
128
116
  - gemfiles/rails3.gemfile.lock
129
117
  - gemfiles/rails4_1.gemfile
@@ -162,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
162
150
  version: '0'
163
151
  requirements: []
164
152
  rubyforge_project:
165
- rubygems_version: 2.4.6
153
+ rubygems_version: 2.5.1
166
154
  signing_key:
167
155
  specification_version: 4
168
156
  summary: Automatically add calculated attributes to ActiveRecord models.