activerecord-traits 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +62 -0
- data/Rakefile +1 -0
- data/activerecord-traits.gemspec +24 -0
- data/lib/activerecord-traits.rb +44 -0
- data/lib/traits/association.rb +39 -0
- data/lib/traits/attribute.rb +52 -0
- data/lib/traits/base.rb +7 -0
- data/lib/traits/concerns/association/essay_shortcuts.rb +9 -0
- data/lib/traits/concerns/association/intermediate.rb +55 -0
- data/lib/traits/concerns/association/join.rb +89 -0
- data/lib/traits/concerns/association/macro.rb +43 -0
- data/lib/traits/concerns/association/members.rb +35 -0
- data/lib/traits/concerns/association/naming.rb +15 -0
- data/lib/traits/concerns/association/polymorphism.rb +118 -0
- data/lib/traits/concerns/association/read_only.rb +17 -0
- data/lib/traits/concerns/association/through.rb +72 -0
- data/lib/traits/concerns/attribute/essay_shortcuts.rb +9 -0
- data/lib/traits/concerns/attribute/key.rb +38 -0
- data/lib/traits/concerns/attribute/naming.rb +20 -0
- data/lib/traits/concerns/attribute/polymorphism.rb +28 -0
- data/lib/traits/concerns/attribute/querying.rb +14 -0
- data/lib/traits/concerns/attribute/sti.rb +15 -0
- data/lib/traits/concerns/attribute/type.rb +59 -0
- data/lib/traits/concerns/model/essay_shortcuts.rb +9 -0
- data/lib/traits/concerns/model/naming.rb +83 -0
- data/lib/traits/concerns/model/polymorphism.rb +15 -0
- data/lib/traits/concerns/model/querying.rb +34 -0
- data/lib/traits/concerns/model/sti.rb +41 -0
- data/lib/traits/descendants_listing.rb +51 -0
- data/lib/traits/engine.rb +13 -0
- data/lib/traits/list.rb +52 -0
- data/lib/traits/model.rb +78 -0
- data/lib/traits/utilities.rb +37 -0
- data/lib/traits/version.rb +3 -0
- metadata +151 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
module Traits
|
2
|
+
class Association
|
3
|
+
module Macro
|
4
|
+
delegate :macro, to: :reflection
|
5
|
+
|
6
|
+
def short_macro
|
7
|
+
habtm? ? :habtm : macro
|
8
|
+
end
|
9
|
+
|
10
|
+
def has_and_belongs_to_many?
|
11
|
+
macro == :has_and_belongs_to_many
|
12
|
+
end
|
13
|
+
|
14
|
+
alias habtm? has_and_belongs_to_many?
|
15
|
+
|
16
|
+
def has_many?
|
17
|
+
macro == :has_many
|
18
|
+
end
|
19
|
+
|
20
|
+
def has_one?
|
21
|
+
macro == :has_one
|
22
|
+
end
|
23
|
+
|
24
|
+
def belongs_to?
|
25
|
+
macro == :belongs_to
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_many?
|
29
|
+
has_and_belongs_to_many? || has_many?
|
30
|
+
end
|
31
|
+
|
32
|
+
alias collection? to_many?
|
33
|
+
|
34
|
+
def to_one?
|
35
|
+
belongs_to? || has_one?
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_hash
|
39
|
+
super.merge!(macro: macro, collection: collection?)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Traits
|
2
|
+
class Association
|
3
|
+
module Members
|
4
|
+
def from
|
5
|
+
@from_class.traits
|
6
|
+
end
|
7
|
+
|
8
|
+
# Returns the actual association establisher class
|
9
|
+
def from_class
|
10
|
+
@from_class
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns the actual associated class
|
14
|
+
def to
|
15
|
+
reflection.klass.traits unless polymorphic?
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_class
|
19
|
+
reflection.klass unless polymorphic?
|
20
|
+
end
|
21
|
+
|
22
|
+
def self_to_self?
|
23
|
+
from_class == to_class
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_hash
|
27
|
+
super.merge!(
|
28
|
+
from: from.name,
|
29
|
+
to: to.try(:name),
|
30
|
+
self_to_self: self_to_self?
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Traits
|
2
|
+
class Association
|
3
|
+
module Polymorphism
|
4
|
+
# class Picture
|
5
|
+
# belongs_to :imageable, polymorphic: true
|
6
|
+
#
|
7
|
+
# class Toy
|
8
|
+
# has_one :picture, as: :imageable
|
9
|
+
#
|
10
|
+
# picture_traits.associations[:imageable].polymorphic? => true
|
11
|
+
# toy_traits.associations[:picture].polymorphic? => false
|
12
|
+
#
|
13
|
+
def polymorphic?
|
14
|
+
belongs_to? && reflection.options[:polymorphic] == true
|
15
|
+
end
|
16
|
+
|
17
|
+
alias accepts_various_classes? polymorphic?
|
18
|
+
|
19
|
+
# Example 1:
|
20
|
+
# class Picture
|
21
|
+
# belongs_to :imageable, polymorphic: true
|
22
|
+
#
|
23
|
+
# class Toy
|
24
|
+
# has_one :picture, as: :imageable
|
25
|
+
#
|
26
|
+
# picture_traits.associations[:imageable].accepted_classes_through_polymorphism
|
27
|
+
# => [Toy]
|
28
|
+
#
|
29
|
+
# toy_traits.associations[:picture].accepted_classes_through_polymorphism
|
30
|
+
# => nil
|
31
|
+
#
|
32
|
+
# Example 2:
|
33
|
+
# class Picture
|
34
|
+
# belongs_to :imageable, polymorphic: true
|
35
|
+
#
|
36
|
+
# class Present
|
37
|
+
# has_one :picture, as: :imageable
|
38
|
+
#
|
39
|
+
# class Toy < Present
|
40
|
+
# class VideoGame < Present
|
41
|
+
# class Car < Present
|
42
|
+
#
|
43
|
+
# picture_traits.associations[:imageable].accepted_classes_through_polymorphism
|
44
|
+
# => [Car, Present, Toy, VideoGame]
|
45
|
+
#
|
46
|
+
# Note that items in list are sorted by class name
|
47
|
+
#
|
48
|
+
def accepted_classes_through_polymorphism
|
49
|
+
if polymorphic?
|
50
|
+
classes = []
|
51
|
+
attr_name = attribute_name_for_polymorphic_type
|
52
|
+
this_class = from_class
|
53
|
+
|
54
|
+
Traits.active_record_descendants.each do |model_class|
|
55
|
+
# Skip current model and models which are STI derived
|
56
|
+
next if model_class <= this_class # Means is or derived from current model
|
57
|
+
|
58
|
+
model_class.traits.associations.each do |assoc|
|
59
|
+
if assoc.attribute_name_for_polymorphic_type == attr_name
|
60
|
+
classes << assoc.from_class
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
classes.uniq.sort! { |l, r| l.to_s <=> r.to_s }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# class Picture
|
69
|
+
# belongs_to :imageable, polymorphic: true
|
70
|
+
#
|
71
|
+
# class Toy
|
72
|
+
# has_one :picture, as: :imageable
|
73
|
+
#
|
74
|
+
# picture_traits.associations[:imageable].paired_through_polymorphism? => false
|
75
|
+
# toy_traits.associations[:picture].paired_through_polymorphism? => true
|
76
|
+
#
|
77
|
+
def paired_through_polymorphism?
|
78
|
+
reflection.type.present?
|
79
|
+
end
|
80
|
+
|
81
|
+
# class Picture
|
82
|
+
# belongs_to :imageable, polymorphic: true
|
83
|
+
#
|
84
|
+
# class Toy
|
85
|
+
# has_one :picture, as: :imageable
|
86
|
+
#
|
87
|
+
# picture_traits.associations[:imageable].polymorphic_type_attribute_name => :imageable_type
|
88
|
+
# toy_traits.associations[:picture].polymorphic_type_attribute_name => :imageable_type
|
89
|
+
#
|
90
|
+
def attribute_name_for_polymorphic_type
|
91
|
+
if polymorphic?
|
92
|
+
reflection.foreign_type.to_sym
|
93
|
+
elsif paired_through_polymorphism?
|
94
|
+
reflection.type.to_sym
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def attribute_for_polymorphic_type
|
99
|
+
if polymorphic?
|
100
|
+
from.attributes[attribute_for_polymorphic_type]
|
101
|
+
elsif paired_through_polymorphism?
|
102
|
+
to.attributes[reflection.foreign_type]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_hash
|
107
|
+
accepted_classes = accepted_classes_through_polymorphism
|
108
|
+
super.merge!(
|
109
|
+
polymorphic: polymorphic?,
|
110
|
+
paired_through_polymorphism: paired_through_polymorphism?,
|
111
|
+
|
112
|
+
attribute_name_for_polymorphic_type: attribute_name_for_polymorphic_type,
|
113
|
+
accepted_classes_through_polymorphism: accepted_classes.try(:map) { |el| el.traits.name }
|
114
|
+
)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Traits
|
2
|
+
class Association
|
3
|
+
module ReadOnly
|
4
|
+
def mutable?
|
5
|
+
!through? || source_association.macro == :belongs_to
|
6
|
+
end
|
7
|
+
|
8
|
+
def readonly?
|
9
|
+
not mutable?
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_hash
|
13
|
+
super.merge!(mutable: mutable?)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Traits
|
2
|
+
class Association
|
3
|
+
module Through
|
4
|
+
def through?
|
5
|
+
reflection.through_reflection.present?
|
6
|
+
end
|
7
|
+
|
8
|
+
def through
|
9
|
+
if through?
|
10
|
+
reflection.through_reflection.klass.traits
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def through_class
|
15
|
+
if through?
|
16
|
+
through.active_record
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def through_association
|
21
|
+
if through?
|
22
|
+
from.associations[reflection.through_reflection.name]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def source_association
|
27
|
+
if through?
|
28
|
+
through.associations[reflection.source_reflection.name]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def source_association_name
|
33
|
+
source_association.try(:name)
|
34
|
+
end
|
35
|
+
|
36
|
+
def through_association_name
|
37
|
+
if through?
|
38
|
+
through_association.name
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def through_table_name
|
43
|
+
if through?
|
44
|
+
through_association.to_table_name
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def through_to_key_name
|
49
|
+
if through?
|
50
|
+
through_association.to_key_name
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def through_from_key_name
|
55
|
+
if through?
|
56
|
+
source_association.from_key_name
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_hash
|
61
|
+
super.merge!(
|
62
|
+
through: through.try(:name),
|
63
|
+
through_association: through_association_name,
|
64
|
+
source_association: source_association_name,
|
65
|
+
through_table_name: through_table_name,
|
66
|
+
through_to_key_name: through_to_key_name,
|
67
|
+
through_from_key_name: through_from_key_name
|
68
|
+
)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Traits
|
2
|
+
class Attribute
|
3
|
+
module Key
|
4
|
+
def primary_key?
|
5
|
+
column_definition.try(:primary) ||
|
6
|
+
model_class.primary_key == column_definition.name ||
|
7
|
+
type == :primary_key
|
8
|
+
end
|
9
|
+
|
10
|
+
def foreign_key?
|
11
|
+
attr_name = name
|
12
|
+
attr_translates = model_class.attribute_features[attr_name].translates_with_globalize?
|
13
|
+
|
14
|
+
model.associations.any? do |assoc|
|
15
|
+
if assoc.belongs_to?
|
16
|
+
if attr_translates && assoc.features.translates_with_globalize?
|
17
|
+
assoc.features.globalize_translatable.translation_from_key_name == attr_name
|
18
|
+
else
|
19
|
+
assoc.from_key_name == attr_name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def key?
|
26
|
+
primary_key? || foreign_key? || polymorphic_key?
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_hash
|
30
|
+
super.merge!(
|
31
|
+
key: key?,
|
32
|
+
primary_key: primary_key?,
|
33
|
+
foreign_key: foreign_key?
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Traits
|
2
|
+
class Attribute
|
3
|
+
module Naming
|
4
|
+
def name
|
5
|
+
column_definition.name.to_sym
|
6
|
+
end
|
7
|
+
|
8
|
+
def quoted_name
|
9
|
+
model_class.connection.quote_column_name(name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_hash
|
13
|
+
super.merge!(
|
14
|
+
name: name,
|
15
|
+
quoted_name: quoted_name
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Traits
|
2
|
+
class Attribute
|
3
|
+
module Polymorphism
|
4
|
+
def polymorphic_key?
|
5
|
+
model.associations
|
6
|
+
.first_where(
|
7
|
+
polymorphic?: true,
|
8
|
+
from_key_name: name
|
9
|
+
).present?
|
10
|
+
end
|
11
|
+
|
12
|
+
def polymorphic_type?
|
13
|
+
model.associations
|
14
|
+
.first_where(
|
15
|
+
polymorphic?: true,
|
16
|
+
attribute_name_for_polymorphic_type: name
|
17
|
+
).present?
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
super.merge!(
|
22
|
+
polymorphic_key: polymorphic_key?,
|
23
|
+
polymorphic_type: polymorphic_type?
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Traits
|
2
|
+
class Attribute
|
3
|
+
module Type
|
4
|
+
def type
|
5
|
+
column_definition.type.to_sym
|
6
|
+
end
|
7
|
+
|
8
|
+
def string?
|
9
|
+
type == :string
|
10
|
+
end
|
11
|
+
|
12
|
+
def text?
|
13
|
+
type == :text
|
14
|
+
end
|
15
|
+
|
16
|
+
def binary?
|
17
|
+
type == :binary
|
18
|
+
end
|
19
|
+
|
20
|
+
def big?
|
21
|
+
text? || binary?
|
22
|
+
end
|
23
|
+
|
24
|
+
def integer?
|
25
|
+
type == :integer
|
26
|
+
end
|
27
|
+
|
28
|
+
def float?
|
29
|
+
type == :float
|
30
|
+
end
|
31
|
+
|
32
|
+
def decimal?
|
33
|
+
type == :decimal
|
34
|
+
end
|
35
|
+
|
36
|
+
def real?
|
37
|
+
float? || decimal?
|
38
|
+
end
|
39
|
+
|
40
|
+
def number?
|
41
|
+
integer? || float? || decimal?
|
42
|
+
end
|
43
|
+
|
44
|
+
def datetime?
|
45
|
+
type == :datetime
|
46
|
+
end
|
47
|
+
|
48
|
+
def active_record_timestamp?
|
49
|
+
datetime? && (name == :created_at || name == :updated_at || name == :deleted_at)
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_hash
|
53
|
+
super.merge!(
|
54
|
+
type: type
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|