multi_tabular 0.0.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 92cbe3c16e1fc9900bea20bb3639e58ebc986ba3
4
+ data.tar.gz: 4c0b92455f9d66494462fae3df726388f77144b2
5
+ SHA512:
6
+ metadata.gz: 507ccebc9e858d9dc1ef6369eddc49d0cd25840c64e90120fa91c11c6ecf5e9e54fd231bec76394ed5791fc6a02ece1eed7d2ab1cf438f836faf976847965e85
7
+ data.tar.gz: b3e5d0b1702d0a503c748ac62192889859bf9fe48131215f8642ec83757f0474f4c9955221b82cdc57dd466c18781e1c1c4abd61cf02349da10b6866ea6f8551
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Gem's dependencies are specified in multitabular.gemspec
4
+ gemspec
@@ -0,0 +1,9 @@
1
+ require 'multi_tabular/references'
2
+ require 'multi_tabular/super'
3
+ require 'multi_tabular/sub'
4
+ require 'multi_tabular/version'
5
+
6
+ module MultiTabular
7
+ class InvalidBaseClassError
8
+ end
9
+ end
@@ -0,0 +1,91 @@
1
+ module MultiTabular
2
+ # For classes that reference an MTI class
3
+ module References
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ def reflection_assignment_method(klass)
8
+ self.class.reflect_on_association(reflection_symbol(klass)).name.to_s + '='
9
+ end
10
+
11
+ def reflection_assignment_symbol(sym)
12
+ self.class.reflect_on_association(sym).name.to_s + '='
13
+ end
14
+
15
+ # for all subclasses of the given base class, returns a
16
+ # list of defined associations within the current class
17
+ def association_methods(mti_base_class)
18
+ (mti_base_class.descendants << mti_base_class).map{|s|
19
+ assoc = self.class.reflect_on_association(reflection_symbol s)
20
+ assoc ? assoc.name : nil
21
+ }.compact
22
+ end
23
+
24
+ # for a given class, returns the appropriate symbol
25
+ # to pass to the ActiveRecord method reflect_on_association
26
+ def reflection_symbol(klass)
27
+ klass.to_s.sub('::', '_').underscore.to_sym
28
+ end
29
+ end
30
+
31
+ module ClassMethods
32
+ # create a polymorphic association to an MTI construct in a belongs_to fashion,
33
+ # meaning that the table of the class including this mixin has a foreign key to each of the MTI construct's
34
+ # concrete models. It defines a getter and setter method named like the assoc_sym argument.
35
+ # The method tries to guess the base class itself based on the association name, but if namespaces or an arbitrary
36
+ # association name is used, the name of the base class should be passed as string with base_class: 'BaseClassName"
37
+ def belongs_to_mti(assoc_sym, params = {})
38
+ # Check if guessed or passed in constant is a class and is a descendant of ActiveRecord::Base
39
+ def validate_base_class(bc)
40
+ bc.is_a?(Class) && bc < ActiveRecord::Base
41
+ end
42
+
43
+ # for a given class, returns the appropriate symbol
44
+ # to pass to the ActiveRecord method reflect_on_association
45
+ def reflection_symbol(klass)
46
+ klass.to_s.sub('::', '_').underscore.to_sym
47
+ end
48
+
49
+ if params.key? :base_class
50
+ base_class = Module.const_get params[:base_class]
51
+ else
52
+ base_class = Module.const_get assoc_sym.capitalize
53
+ end
54
+
55
+ # Raise an error if the base class doesn't saturate the conditions.
56
+ unless validate_base_class base_class
57
+ fail InvalidBaseClassError.new "#{base_class} is not a valid base class."
58
+ end
59
+
60
+ # Define the getter method for retrieving a referenced MTI record.
61
+ # Each association method for the base class is invoked and first that returns a result will be used.
62
+ define_method(assoc_sym.to_s) do
63
+ association_methods(base_class).map do|a|
64
+ send a
65
+ end.reduce do |a, b|
66
+ a || b
67
+ end
68
+ end
69
+
70
+ define_method("count_#{assoc_sym.to_s.pluralize}") do
71
+ association_methods(base_class).reduce(0) do |sum, method|
72
+ send(method) ? sum + 1 : sum
73
+ end
74
+ end
75
+
76
+ # Define the setter method that dynamically accesses the concrete setter for the type of the assignee.
77
+ define_method("#{assoc_sym}=") do |assignee|
78
+ association_methods(base_class).each do |association|
79
+ send reflection_assignment_symbol(association), nil
80
+ end
81
+
82
+ send reflection_assignment_method(assignee.class), assignee
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ class ActiveRecord::Base
90
+ include MultiTabular::References
91
+ end
@@ -0,0 +1,13 @@
1
+ module MultiTabular
2
+ # For subclasses of an MTI construct.
3
+ # These classes inherit logic from a superclass and are persisted in their own table.
4
+ module Sub
5
+ extend ActiveSupport::Concern
6
+
7
+ # Set the table name to be the class name, including namespaces.
8
+ # If a different table should be used, override this variable in your class.
9
+ included do
10
+ self.table_name = name.underscore.sub('/', '_').pluralize
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module MultiTabular
2
+ # For superclasses of an MTI construct.
3
+ # These classes can provide shared logic, but are not an activerecord-model on their own,
4
+ # meaning they have no corresponding table in the database.
5
+ module Super
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ self.abstract_class = true
10
+
11
+ # Allow converting the class name to an assumed foreign key in an associated model's database.
12
+ # If a different foreign should be used, you can override this method or simply declare the foreign key manually.
13
+ def self.to_foreign_key
14
+ name.underscore.sub('/', '_').singularize << '_id'
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module MultiTabular
2
+ VERSION = '0.0.2'
3
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: multi_tabular
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Alexander Junger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
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: activerecord
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '4.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '4.1'
41
+ description: |-
42
+ Facilitates true multi table inheritance of ActiveRecord models by providing methods for
43
+ super- and subclasses as well as models with a foreign-key association to MTI records.
44
+ email: hello@alexanderjunger.at
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - Gemfile
50
+ - lib/multi_tabular.rb
51
+ - lib/multi_tabular/references.rb
52
+ - lib/multi_tabular/sub.rb
53
+ - lib/multi_tabular/super.rb
54
+ - lib/multi_tabular/version.rb
55
+ homepage:
56
+ licenses:
57
+ - MIT
58
+ metadata: {}
59
+ post_install_message:
60
+ rdoc_options: []
61
+ require_paths:
62
+ - lib
63
+ required_ruby_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '2.0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ requirements: []
74
+ rubyforge_project:
75
+ rubygems_version: 2.4.4
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: True multi table inheritance for ActiveRecord.
79
+ test_files: []