activerecord-traits 1.0.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.
- 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
|