association_accessors 1.3.0

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.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/Appraisals +25 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +254 -0
  7. data/Rakefile +27 -0
  8. data/association_accessors.gemspec +39 -0
  9. data/bin/test +21 -0
  10. data/gemfiles/activerecord_4.1.gemfile +7 -0
  11. data/gemfiles/activerecord_4.1.gemfile.lock +67 -0
  12. data/gemfiles/activerecord_4.2.gemfile +7 -0
  13. data/gemfiles/activerecord_4.2.gemfile.lock +67 -0
  14. data/gemfiles/activerecord_5.0.gemfile +7 -0
  15. data/gemfiles/activerecord_5.0.gemfile.lock +63 -0
  16. data/gemfiles/activerecord_5.1.gemfile +7 -0
  17. data/gemfiles/activerecord_5.1.gemfile.lock +63 -0
  18. data/gemfiles/activerecord_5.2.gemfile +7 -0
  19. data/gemfiles/activerecord_5.2.gemfile.lock +63 -0
  20. data/gemfiles/rspec_2.gemfile +7 -0
  21. data/gemfiles/rspec_2.gemfile.lock +58 -0
  22. data/lib/association_accessors.rb +30 -0
  23. data/lib/association_accessors/collection_association.rb +35 -0
  24. data/lib/association_accessors/singular_association.rb +19 -0
  25. data/lib/association_accessors/test/matcher.rb +60 -0
  26. data/lib/association_accessors/version.rb +3 -0
  27. data/spec/association_accessors_spec.rb +5 -0
  28. data/spec/dummy.rb +99 -0
  29. data/spec/matcher_spec.rb +56 -0
  30. data/spec/spec_helper.rb +23 -0
  31. data/spec/with_association/belongs_to_spec.rb +33 -0
  32. data/spec/with_association/has_and_belongs_to_many_spec.rb +45 -0
  33. data/spec/with_association/has_many_spec.rb +45 -0
  34. data/spec/with_association/has_many_through_spec.rb +27 -0
  35. data/spec/with_association/has_one_spec.rb +33 -0
  36. data/spec/with_association/has_one_through_spec.rb +43 -0
  37. data/spec/with_association/polymorphic/belongs_to_spec.rb +38 -0
  38. data/spec/with_association/polymorphic/has_many_spec.rb +44 -0
  39. data/spec/with_association/polymorphic/has_one_spec.rb +33 -0
  40. data/spec/with_association/with_custom_name_spec.rb +33 -0
  41. data/spec/with_attribute_spec.rb +47 -0
  42. metadata +203 -0
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "4.2.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,67 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ association_accessors (1.3.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (4.2.0)
10
+ activesupport (= 4.2.0)
11
+ builder (~> 3.1)
12
+ activerecord (4.2.0)
13
+ activemodel (= 4.2.0)
14
+ activesupport (= 4.2.0)
15
+ arel (~> 6.0)
16
+ activesupport (4.2.0)
17
+ i18n (~> 0.7)
18
+ json (~> 1.7, >= 1.7.7)
19
+ minitest (~> 5.1)
20
+ thread_safe (~> 0.3, >= 0.3.4)
21
+ tzinfo (~> 1.1)
22
+ appraisal (2.2.0)
23
+ bundler
24
+ rake
25
+ thor (>= 0.14.0)
26
+ arel (6.0.4)
27
+ builder (3.2.3)
28
+ concurrent-ruby (1.1.4)
29
+ diff-lcs (1.3)
30
+ i18n (0.9.5)
31
+ concurrent-ruby (~> 1.0)
32
+ json (1.8.6)
33
+ minitest (5.11.3)
34
+ rake (10.5.0)
35
+ rspec (3.8.0)
36
+ rspec-core (~> 3.8.0)
37
+ rspec-expectations (~> 3.8.0)
38
+ rspec-mocks (~> 3.8.0)
39
+ rspec-core (3.8.0)
40
+ rspec-support (~> 3.8.0)
41
+ rspec-expectations (3.8.2)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.8.0)
44
+ rspec-mocks (3.8.0)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.8.0)
47
+ rspec-support (3.8.0)
48
+ sqlite3 (1.3.13)
49
+ thor (0.20.3)
50
+ thread_safe (0.3.6)
51
+ tzinfo (1.2.5)
52
+ thread_safe (~> 0.1)
53
+
54
+ PLATFORMS
55
+ ruby
56
+
57
+ DEPENDENCIES
58
+ activerecord (= 4.2.0)
59
+ appraisal (~> 2.2)
60
+ association_accessors!
61
+ bundler (~> 1.16)
62
+ rake (~> 10.0)
63
+ rspec (~> 3.0)
64
+ sqlite3 (~> 1.3)
65
+
66
+ BUNDLED WITH
67
+ 1.16.6
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "5.0.3"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,63 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ association_accessors (1.3.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (5.0.3)
10
+ activesupport (= 5.0.3)
11
+ activerecord (5.0.3)
12
+ activemodel (= 5.0.3)
13
+ activesupport (= 5.0.3)
14
+ arel (~> 7.0)
15
+ activesupport (5.0.3)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (~> 0.7)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ appraisal (2.2.0)
21
+ bundler
22
+ rake
23
+ thor (>= 0.14.0)
24
+ arel (7.1.4)
25
+ concurrent-ruby (1.1.4)
26
+ diff-lcs (1.3)
27
+ i18n (0.9.5)
28
+ concurrent-ruby (~> 1.0)
29
+ minitest (5.11.3)
30
+ rake (10.5.0)
31
+ rspec (3.8.0)
32
+ rspec-core (~> 3.8.0)
33
+ rspec-expectations (~> 3.8.0)
34
+ rspec-mocks (~> 3.8.0)
35
+ rspec-core (3.8.0)
36
+ rspec-support (~> 3.8.0)
37
+ rspec-expectations (3.8.2)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.8.0)
40
+ rspec-mocks (3.8.0)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.8.0)
43
+ rspec-support (3.8.0)
44
+ sqlite3 (1.3.13)
45
+ thor (0.20.3)
46
+ thread_safe (0.3.6)
47
+ tzinfo (1.2.5)
48
+ thread_safe (~> 0.1)
49
+
50
+ PLATFORMS
51
+ ruby
52
+
53
+ DEPENDENCIES
54
+ activerecord (= 5.0.3)
55
+ appraisal (~> 2.2)
56
+ association_accessors!
57
+ bundler (~> 1.16)
58
+ rake (~> 10.0)
59
+ rspec (~> 3.0)
60
+ sqlite3 (~> 1.3)
61
+
62
+ BUNDLED WITH
63
+ 1.16.6
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "5.1.5"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,63 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ association_accessors (1.3.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (5.1.5)
10
+ activesupport (= 5.1.5)
11
+ activerecord (5.1.5)
12
+ activemodel (= 5.1.5)
13
+ activesupport (= 5.1.5)
14
+ arel (~> 8.0)
15
+ activesupport (5.1.5)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (~> 0.7)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ appraisal (2.2.0)
21
+ bundler
22
+ rake
23
+ thor (>= 0.14.0)
24
+ arel (8.0.0)
25
+ concurrent-ruby (1.1.4)
26
+ diff-lcs (1.3)
27
+ i18n (0.9.5)
28
+ concurrent-ruby (~> 1.0)
29
+ minitest (5.11.3)
30
+ rake (10.5.0)
31
+ rspec (3.8.0)
32
+ rspec-core (~> 3.8.0)
33
+ rspec-expectations (~> 3.8.0)
34
+ rspec-mocks (~> 3.8.0)
35
+ rspec-core (3.8.0)
36
+ rspec-support (~> 3.8.0)
37
+ rspec-expectations (3.8.2)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.8.0)
40
+ rspec-mocks (3.8.0)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.8.0)
43
+ rspec-support (3.8.0)
44
+ sqlite3 (1.3.13)
45
+ thor (0.20.3)
46
+ thread_safe (0.3.6)
47
+ tzinfo (1.2.5)
48
+ thread_safe (~> 0.1)
49
+
50
+ PLATFORMS
51
+ ruby
52
+
53
+ DEPENDENCIES
54
+ activerecord (= 5.1.5)
55
+ appraisal (~> 2.2)
56
+ association_accessors!
57
+ bundler (~> 1.16)
58
+ rake (~> 10.0)
59
+ rspec (~> 3.0)
60
+ sqlite3 (~> 1.3)
61
+
62
+ BUNDLED WITH
63
+ 1.16.6
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "5.2.2"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,63 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ association_accessors (1.3.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (5.2.2)
10
+ activesupport (= 5.2.2)
11
+ activerecord (5.2.2)
12
+ activemodel (= 5.2.2)
13
+ activesupport (= 5.2.2)
14
+ arel (>= 9.0)
15
+ activesupport (5.2.2)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 0.7, < 2)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ appraisal (2.2.0)
21
+ bundler
22
+ rake
23
+ thor (>= 0.14.0)
24
+ arel (9.0.0)
25
+ concurrent-ruby (1.1.4)
26
+ diff-lcs (1.3)
27
+ i18n (1.5.3)
28
+ concurrent-ruby (~> 1.0)
29
+ minitest (5.11.3)
30
+ rake (10.5.0)
31
+ rspec (3.8.0)
32
+ rspec-core (~> 3.8.0)
33
+ rspec-expectations (~> 3.8.0)
34
+ rspec-mocks (~> 3.8.0)
35
+ rspec-core (3.8.0)
36
+ rspec-support (~> 3.8.0)
37
+ rspec-expectations (3.8.2)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.8.0)
40
+ rspec-mocks (3.8.0)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.8.0)
43
+ rspec-support (3.8.0)
44
+ sqlite3 (1.3.13)
45
+ thor (0.20.3)
46
+ thread_safe (0.3.6)
47
+ tzinfo (1.2.5)
48
+ thread_safe (~> 0.1)
49
+
50
+ PLATFORMS
51
+ ruby
52
+
53
+ DEPENDENCIES
54
+ activerecord (= 5.2.2)
55
+ appraisal (~> 2.2)
56
+ association_accessors!
57
+ bundler (~> 1.16)
58
+ rake (~> 10.0)
59
+ rspec (~> 3.0)
60
+ sqlite3 (~> 1.3)
61
+
62
+ BUNDLED WITH
63
+ 1.16.6
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rspec", "~> 2.0"
6
+
7
+ gemspec path: "../"
@@ -0,0 +1,58 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ association_accessors (1.3.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ activemodel (5.2.2)
10
+ activesupport (= 5.2.2)
11
+ activerecord (5.2.2)
12
+ activemodel (= 5.2.2)
13
+ activesupport (= 5.2.2)
14
+ arel (>= 9.0)
15
+ activesupport (5.2.2)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 0.7, < 2)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ appraisal (2.2.0)
21
+ bundler
22
+ rake
23
+ thor (>= 0.14.0)
24
+ arel (9.0.0)
25
+ concurrent-ruby (1.1.4)
26
+ diff-lcs (1.3)
27
+ i18n (1.5.3)
28
+ concurrent-ruby (~> 1.0)
29
+ minitest (5.11.3)
30
+ rake (10.5.0)
31
+ rspec (2.99.0)
32
+ rspec-core (~> 2.99.0)
33
+ rspec-expectations (~> 2.99.0)
34
+ rspec-mocks (~> 2.99.0)
35
+ rspec-core (2.99.2)
36
+ rspec-expectations (2.99.2)
37
+ diff-lcs (>= 1.1.3, < 2.0)
38
+ rspec-mocks (2.99.4)
39
+ sqlite3 (1.3.13)
40
+ thor (0.20.3)
41
+ thread_safe (0.3.6)
42
+ tzinfo (1.2.5)
43
+ thread_safe (~> 0.1)
44
+
45
+ PLATFORMS
46
+ ruby
47
+
48
+ DEPENDENCIES
49
+ activerecord (~> 5.2)
50
+ appraisal (~> 2.2)
51
+ association_accessors!
52
+ bundler (~> 1.16)
53
+ rake (~> 10.0)
54
+ rspec (~> 2.0)
55
+ sqlite3 (~> 1.3)
56
+
57
+ BUNDLED WITH
58
+ 1.16.6
@@ -0,0 +1,30 @@
1
+ require "association_accessors/version"
2
+ require "association_accessors/singular_association"
3
+ require "association_accessors/collection_association"
4
+ require "association_accessors/test/matcher"
5
+
6
+ module AssociationAccessors
7
+ class << self
8
+ attr_accessor :default_attribute
9
+ end
10
+
11
+ def self.included base
12
+ base.extend ClassMethods
13
+ end
14
+
15
+ module ClassMethods
16
+ def association_accessor_for(association_name, with_attribute: nil)
17
+ mixin = generated_association_methods
18
+ reflection = reflect_on_association association_name
19
+
20
+ with_attribute ||= AssociationAccessors.default_attribute
21
+ raise ArgumentError, 'missing keyword: with_attribute' if with_attribute.nil?
22
+
23
+ if reflection.collection?
24
+ CollectionAssociation.define_association_methods mixin, reflection, with_attribute
25
+ else
26
+ SingularAssociation.define_association_methods mixin, reflection, with_attribute
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,35 @@
1
+ module AssociationAccessors
2
+ class CollectionAssociation
3
+ def self.define_association_methods mixin, reflection, attribute
4
+ association = reflection.name
5
+ method_name = "#{association.to_s.singularize}_#{attribute.to_s.pluralize}"
6
+
7
+ raise_not_found_parameter_count = ActiveRecord::Relation.instance_method(:raise_record_not_found_exception!).parameters.size
8
+ raise_not_found_parameters = %W[
9
+ values.map(&:inspect)
10
+ records.size
11
+ values.size
12
+ :#{attribute}
13
+ not_found_values.map(&:inspect)
14
+ ][0...raise_not_found_parameter_count]
15
+
16
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
17
+ def #{method_name}
18
+ #{association}.map &:#{attribute}
19
+ end
20
+
21
+ def #{method_name}= values
22
+ association_class = association(#{association.inspect}).klass
23
+ values = Array(values).reject &:blank?
24
+ records = association_class.where(#{attribute}: values).index_by(&:#{attribute}).values_at(*values).compact
25
+ if records.size == values.size
26
+ send :#{association}=, records
27
+ else
28
+ not_found_values = values - records.map(&:#{attribute})
29
+ association_class.all.raise_record_not_found_exception! #{raise_not_found_parameters.join ', '}
30
+ end
31
+ end
32
+ CODE
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ module AssociationAccessors
2
+ class SingularAssociation
3
+ def self.define_association_methods mixin, reflection, attribute
4
+ association = reflection.name
5
+
6
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
7
+ def #{association}_#{attribute}
8
+ #{association}&.#{attribute}
9
+ end
10
+
11
+ def #{association}_#{attribute}= value
12
+ association_class = association(#{association.inspect}).klass
13
+ send :#{association}=, value && association_class.find_by!(#{attribute}: value)
14
+ value
15
+ end
16
+ CODE
17
+ end
18
+ end
19
+ end