activerecord-traits 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/Gemfile +8 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +62 -0
  6. data/Rakefile +1 -0
  7. data/activerecord-traits.gemspec +24 -0
  8. data/lib/activerecord-traits.rb +44 -0
  9. data/lib/traits/association.rb +39 -0
  10. data/lib/traits/attribute.rb +52 -0
  11. data/lib/traits/base.rb +7 -0
  12. data/lib/traits/concerns/association/essay_shortcuts.rb +9 -0
  13. data/lib/traits/concerns/association/intermediate.rb +55 -0
  14. data/lib/traits/concerns/association/join.rb +89 -0
  15. data/lib/traits/concerns/association/macro.rb +43 -0
  16. data/lib/traits/concerns/association/members.rb +35 -0
  17. data/lib/traits/concerns/association/naming.rb +15 -0
  18. data/lib/traits/concerns/association/polymorphism.rb +118 -0
  19. data/lib/traits/concerns/association/read_only.rb +17 -0
  20. data/lib/traits/concerns/association/through.rb +72 -0
  21. data/lib/traits/concerns/attribute/essay_shortcuts.rb +9 -0
  22. data/lib/traits/concerns/attribute/key.rb +38 -0
  23. data/lib/traits/concerns/attribute/naming.rb +20 -0
  24. data/lib/traits/concerns/attribute/polymorphism.rb +28 -0
  25. data/lib/traits/concerns/attribute/querying.rb +14 -0
  26. data/lib/traits/concerns/attribute/sti.rb +15 -0
  27. data/lib/traits/concerns/attribute/type.rb +59 -0
  28. data/lib/traits/concerns/model/essay_shortcuts.rb +9 -0
  29. data/lib/traits/concerns/model/naming.rb +83 -0
  30. data/lib/traits/concerns/model/polymorphism.rb +15 -0
  31. data/lib/traits/concerns/model/querying.rb +34 -0
  32. data/lib/traits/concerns/model/sti.rb +41 -0
  33. data/lib/traits/descendants_listing.rb +51 -0
  34. data/lib/traits/engine.rb +13 -0
  35. data/lib/traits/list.rb +52 -0
  36. data/lib/traits/model.rb +78 -0
  37. data/lib/traits/utilities.rb +37 -0
  38. data/lib/traits/version.rb +3 -0
  39. 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,15 @@
1
+ module Traits
2
+ class Association
3
+ module Naming
4
+ delegate :name, to: :reflection
5
+
6
+ def plural_name
7
+ reflection.plural_name.to_sym
8
+ end
9
+
10
+ def to_hash
11
+ super.merge!(name: name, plural_name: plural_name)
12
+ end
13
+ end
14
+ end
15
+ 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,9 @@
1
+ module Traits
2
+ class Attribute
3
+ module EssayShortcuts
4
+ def features
5
+ model_class.attribute_features[name]
6
+ end
7
+ end
8
+ end
9
+ 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,14 @@
1
+ module Traits
2
+ class Attribute
3
+ module Querying
4
+ def arel
5
+ table = if features.translates_with_globalize?
6
+ model_class.features.globalize.translation_model_class.arel_table
7
+ else
8
+ model.arel
9
+ end
10
+ table[name]
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,15 @@
1
+ module Traits
2
+ class Attribute
3
+ module STI
4
+ def sti_type?
5
+ (model.sti_base? || model.sti_derived?) and name == model.sti_attribute_name
6
+ end
7
+
8
+ def to_hash
9
+ super.merge!(
10
+ sti_type: sti_type?
11
+ )
12
+ end
13
+ end
14
+ end
15
+ 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