multi_tabular 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []