activerecord-traits 1.0.0 → 1.0.1

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -5
  3. data/activerecord-traits.gemspec +8 -9
  4. data/lib/activerecord-traits.rb +12 -4
  5. data/lib/traits/{concerns/association → association}/essay_shortcuts.rb +4 -1
  6. data/lib/traits/{concerns/association → association}/intermediate.rb +18 -10
  7. data/lib/traits/{concerns/association → association}/join.rb +4 -1
  8. data/lib/traits/{concerns/association → association}/macro.rb +4 -1
  9. data/lib/traits/{concerns/association → association}/members.rb +4 -1
  10. data/lib/traits/{concerns/association → association}/naming.rb +5 -2
  11. data/lib/traits/{concerns/association → association}/polymorphism.rb +4 -1
  12. data/lib/traits/{concerns/association → association}/read_only.rb +4 -1
  13. data/lib/traits/{concerns/association → association}/through.rb +4 -1
  14. data/lib/traits/association.rb +26 -11
  15. data/lib/traits/{concerns/attribute → attribute}/essay_shortcuts.rb +4 -1
  16. data/lib/traits/attribute/inheritance.rb +17 -0
  17. data/lib/traits/{concerns/attribute → attribute}/key.rb +4 -1
  18. data/lib/traits/{concerns/attribute → attribute}/naming.rb +6 -3
  19. data/lib/traits/{concerns/attribute → attribute}/polymorphism.rb +4 -1
  20. data/lib/traits/{concerns/attribute → attribute}/querying.rb +4 -1
  21. data/lib/traits/{concerns/attribute → attribute}/type.rb +5 -2
  22. data/lib/traits/attribute.rb +26 -11
  23. data/lib/traits/base.rb +4 -1
  24. data/lib/traits/descendants_listing.rb +15 -11
  25. data/lib/traits/list.rb +25 -20
  26. data/lib/traits/{concerns/model → model}/essay_shortcuts.rb +4 -1
  27. data/lib/traits/model/inheritance.rb +76 -0
  28. data/lib/traits/{concerns/model → model}/naming.rb +7 -2
  29. data/lib/traits/{concerns/model → model}/polymorphism.rb +5 -2
  30. data/lib/traits/{concerns/model → model}/querying.rb +16 -4
  31. data/lib/traits/model.rb +39 -23
  32. data/lib/traits/{engine.rb → railtie.rb} +6 -5
  33. data/lib/traits/utilities.rb +4 -1
  34. data/lib/traits/version.rb +5 -2
  35. metadata +44 -74
  36. data/Rakefile +0 -1
  37. data/lib/traits/concerns/attribute/sti.rb +0 -15
  38. data/lib/traits/concerns/model/sti.rb +0 -41
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c19a931c6cf49fc903d0a26157fcee1e76c71115
4
- data.tar.gz: 572102c9adbf4c8e0a751e9b18cdaac4bfb40620
3
+ metadata.gz: bdc960c412f73aa79f3f666e6654185ce398b6a1
4
+ data.tar.gz: 5afb7670fe9cfe16ab7ab8cc31e650b1b6561590
5
5
  SHA512:
6
- metadata.gz: ef3f143af6c3ec68b3f6c92102b4a581b2b60dc6b32a7a8e4eed0359c3e53b8e337026c699fc33715aad29f0b61ba9a0fa5bd90bb32d3bf35cd97667c68ad787
7
- data.tar.gz: 6e6c4af699dd5e632e07e31c37c1d7f744722ad4f4879f120da471390a6a6a4c6f79ab19e91238f339d2026b60201b4e5750dc96e7c0abe9d1c633fc4b903d12
6
+ metadata.gz: ff75cbae678809042dec2e2b0cdfdbf77f113bbf0f28efd804e0518abca5c4d34defd7b24c9f847031d68688ba25e825d4ffb5fbc886299e34d266f47a45a280
7
+ data.tar.gz: beb6ae1de4639e06c8f4dc4295bf499ee69a9671b513ee8b64b02101854a828fdf96257d122cfd14af4534496e058d1034600602dab8862deab0b371bfaab8d5
data/Gemfile CHANGED
@@ -1,8 +1,7 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  source 'https://rubygems.org'
2
5
 
3
- # Specify your gem's dependencies in confo.gemspec
6
+ # Specify your gem's dependencies in activerecord-traits.gemspec
4
7
  gemspec
5
-
6
- gem 'essay', path: '~/Development/essay'
7
- gem 'essay-globalize', path: '~/Development/essay-globalize'
8
- gem 'essay-carrierwave', path: '~/Development/essay-carrierwave'
@@ -1,13 +1,15 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
2
4
  require File.expand_path('../lib/traits/version', __FILE__)
3
5
 
4
6
  Gem::Specification.new do |s|
5
7
  s.name = 'activerecord-traits'
6
8
  s.version = Traits::VERSION
7
9
  s.authors = ['Yaroslav Konoplov']
8
- s.email = ['yaroslav@inbox.com']
9
- s.summary = 'Type information of ActiveRecord models, attributes and associations'
10
- s.description = 'Type information of ActiveRecord models, attributes and associations'
10
+ s.email = ['eahome00@gmail.com']
11
+ s.summary = 'Type information of activerecord models'
12
+ s.description = 'Type information of activerecord models, attributes and associations in good and clear manner'
11
13
  s.homepage = 'http://github.com/yivo/activerecord-traits'
12
14
  s.license = 'MIT'
13
15
 
@@ -16,9 +18,6 @@ Gem::Specification.new do |s|
16
18
  s.test_files = `git ls-files -z -- {test,spec,features}/*`.split("\x0")
17
19
  s.require_paths = ['lib']
18
20
 
19
- s.add_dependency 'activesupport', '>= 3.2.0'
20
- s.add_dependency 'activerecord', '>= 3.2.0'
21
- s.add_dependency 'essay', '~> 1.0.0'
22
- s.add_dependency 'essay-globalize', '~> 1.0.0'
23
- s.add_dependency 'essay-carrierwave', '~> 1.0.0'
24
- end
21
+ s.add_dependency 'activesupport', '>= 3.0', '< 6.0'
22
+ s.add_dependency 'activerecord', '>= 3.0', '< 6.0'
23
+ end
@@ -1,10 +1,14 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  require 'active_support/all'
2
5
  require 'active_record'
6
+
3
7
  require 'essay'
4
- require 'essay-globalize'
5
- require 'essay-carrierwave'
8
+ require 'essay-globalize' if defined?(Globalize)
9
+ require 'essay-carrierwave' if defined?(CarrierWave)
6
10
 
7
- require 'traits/engine'
11
+ require 'traits/railtie'
8
12
  require 'traits/utilities'
9
13
  require 'traits/descendants_listing'
10
14
  require 'traits/base'
@@ -36,9 +40,13 @@ module Traits
36
40
  end
37
41
  end
38
42
 
43
+ def self.each_attribute(&block)
44
+ each { |traits| traits.attributes.each(&block) }
45
+ end
46
+
39
47
  def self.to_hash
40
48
  each_with_object({}) do |traits, memo|
41
49
  memo[traits.name] = traits.to_hash
42
50
  end
43
51
  end
44
- end
52
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Association
3
6
  module EssayShortcuts
@@ -6,4 +9,4 @@ module Traits
6
9
  end
7
10
  end
8
11
  end
9
- end
12
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Association
3
6
  module Intermediate
@@ -11,34 +14,39 @@ module Traits
11
14
  end
12
15
 
13
16
  def intermediate_table
14
- if intermediate?
15
- Arel::Table.new(reflection.join_table)
16
- end
17
+ Arel::Table.new(reflection.join_table) if intermediate?
17
18
  end
18
19
 
19
20
  def intermediate_table_name
20
- if intermediate?
21
- reflection.join_table
21
+ return unless intermediate?
22
+ unless @im_table_name
23
+ name = reflection.join_table
24
+ @im_table_name = name.kind_of?(String) ? name.to_sym : name
22
25
  end
26
+ @im_table_name
23
27
  end
24
28
 
25
29
  def intermediate_to_key
26
- intermediate_table.try(:[], intermediate_to_key_name)
30
+ if intermediate?
31
+ intermediate_table[intermediate_to_key_name]
32
+ end
27
33
  end
28
34
 
29
35
  def intermediate_to_key_name
30
36
  if intermediate?
31
- reflection.foreign_key.to_sym
37
+ @im_to_key_name ||= reflection.foreign_key.to_sym
32
38
  end
33
39
  end
34
40
 
35
41
  def intermediate_from_key
36
- intermediate_table.try(:[], intermediate_from_key_name)
42
+ if intermediate?
43
+ intermediate_table[intermediate_from_key_name]
44
+ end
37
45
  end
38
46
 
39
47
  def intermediate_from_key_name
40
48
  if intermediate?
41
- reflection.association_foreign_key.to_sym
49
+ @im_from_key_name ||= reflection.association_foreign_key.to_sym
42
50
  end
43
51
  end
44
52
 
@@ -52,4 +60,4 @@ module Traits
52
60
  end
53
61
  end
54
62
  end
55
- end
63
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Association
3
6
  module Join
@@ -86,4 +89,4 @@ module Traits
86
89
  end
87
90
  end
88
91
  end
89
- end
92
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Association
3
6
  module Macro
@@ -40,4 +43,4 @@ module Traits
40
43
  end
41
44
  end
42
45
  end
43
- end
46
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Association
3
6
  module Members
@@ -32,4 +35,4 @@ module Traits
32
35
  end
33
36
  end
34
37
  end
35
- end
38
+ end
@@ -1,10 +1,13 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Association
3
6
  module Naming
4
7
  delegate :name, to: :reflection
5
8
 
6
9
  def plural_name
7
- reflection.plural_name.to_sym
10
+ @plural_name ||= reflection.plural_name.to_sym
8
11
  end
9
12
 
10
13
  def to_hash
@@ -12,4 +15,4 @@ module Traits
12
15
  end
13
16
  end
14
17
  end
15
- end
18
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Association
3
6
  module Polymorphism
@@ -115,4 +118,4 @@ module Traits
115
118
  end
116
119
  end
117
120
  end
118
- end
121
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Association
3
6
  module ReadOnly
@@ -14,4 +17,4 @@ module Traits
14
17
  end
15
18
  end
16
19
  end
17
- end
20
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Association
3
6
  module Through
@@ -69,4 +72,4 @@ module Traits
69
72
  end
70
73
  end
71
74
  end
72
- end
75
+ end
@@ -1,17 +1,20 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Association < Base
3
6
  end
4
7
  end
5
8
 
6
- require 'traits/concerns/association/intermediate'
7
- require 'traits/concerns/association/join'
8
- require 'traits/concerns/association/macro'
9
- require 'traits/concerns/association/members'
10
- require 'traits/concerns/association/naming'
11
- require 'traits/concerns/association/polymorphism'
12
- require 'traits/concerns/association/read_only'
13
- require 'traits/concerns/association/through'
14
- require 'traits/concerns/association/essay_shortcuts'
9
+ require 'traits/association/intermediate'
10
+ require 'traits/association/join'
11
+ require 'traits/association/macro'
12
+ require 'traits/association/members'
13
+ require 'traits/association/naming'
14
+ require 'traits/association/polymorphism'
15
+ require 'traits/association/read_only'
16
+ require 'traits/association/through'
17
+ require 'traits/association/essay_shortcuts'
15
18
 
16
19
  module Traits
17
20
  class Association
@@ -32,8 +35,20 @@ module Traits
32
35
  @reflection = reflection
33
36
  end
34
37
 
35
- def to_s
38
+ def inspect
36
39
  "#{from.class_name}##{name}"
37
40
  end
41
+
42
+ def to_s
43
+ name
44
+ end
45
+
46
+ def value_from(model)
47
+ model.send(name)
48
+ end
49
+
50
+ def validators
51
+ from_class.validators_on(name)
52
+ end
38
53
  end
39
- end
54
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Attribute
3
6
  module EssayShortcuts
@@ -6,4 +9,4 @@ module Traits
6
9
  end
7
10
  end
8
11
  end
9
- end
12
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Traits
5
+ class Attribute
6
+ module Inheritance
7
+ def inheritance_type?
8
+ (model.inheritance_base? || model.inheritance_derived?) and name == model.inheritance_attribute.name
9
+ end
10
+ alias sti_type? inheritance_type?
11
+
12
+ def to_hash
13
+ super.merge!(is_sti_type: sti_type?)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Attribute
3
6
  module Key
@@ -35,4 +38,4 @@ module Traits
35
38
  end
36
39
  end
37
40
  end
38
- end
41
+ end
@@ -1,12 +1,15 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Attribute
3
6
  module Naming
4
7
  def name
5
- column_definition.name.to_sym
8
+ @name ||= column_definition.name.to_sym
6
9
  end
7
10
 
8
11
  def quoted_name
9
- model_class.connection.quote_column_name(name)
12
+ @quoted_name ||= model_class.connection.quote_column_name(name)
10
13
  end
11
14
 
12
15
  def to_hash
@@ -17,4 +20,4 @@ module Traits
17
20
  end
18
21
  end
19
22
  end
20
- end
23
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Attribute
3
6
  module Polymorphism
@@ -25,4 +28,4 @@ module Traits
25
28
  end
26
29
  end
27
30
  end
28
- end
31
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Attribute
3
6
  module Querying
@@ -11,4 +14,4 @@ module Traits
11
14
  end
12
15
  end
13
16
  end
14
- end
17
+ end
@@ -1,8 +1,11 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Attribute
3
6
  module Type
4
7
  def type
5
- column_definition.type.to_sym
8
+ @type ||= column_definition.type.to_sym
6
9
  end
7
10
 
8
11
  def string?
@@ -56,4 +59,4 @@ module Traits
56
59
  end
57
60
  end
58
61
  end
59
- end
62
+ end
@@ -1,15 +1,18 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Attribute < Base
3
6
  end
4
7
  end
5
8
 
6
- require 'traits/concerns/attribute/key'
7
- require 'traits/concerns/attribute/naming'
8
- require 'traits/concerns/attribute/polymorphism'
9
- require 'traits/concerns/attribute/querying'
10
- require 'traits/concerns/attribute/sti'
11
- require 'traits/concerns/attribute/type'
12
- require 'traits/concerns/attribute/essay_shortcuts'
9
+ require 'traits/attribute/key'
10
+ require 'traits/attribute/naming'
11
+ require 'traits/attribute/polymorphism'
12
+ require 'traits/attribute/querying'
13
+ require 'traits/attribute/inheritance'
14
+ require 'traits/attribute/type'
15
+ require 'traits/attribute/essay_shortcuts'
13
16
 
14
17
  module Traits
15
18
  class Attribute
@@ -18,7 +21,7 @@ module Traits
18
21
  include Type
19
22
  include Polymorphism
20
23
  include Querying
21
- include STI
24
+ include Inheritance
22
25
  include EssayShortcuts
23
26
 
24
27
  attr_reader :model_class, :column_definition
@@ -42,11 +45,23 @@ module Traits
42
45
  end
43
46
 
44
47
  def value_from(model_instance)
45
- model_instance[name]
48
+ model_instance.send(name)
46
49
  end
47
50
 
48
- def to_s
51
+ def inspect
49
52
  "#{model}##{name}"
50
53
  end
54
+
55
+ def to_s
56
+ name
57
+ end
58
+
59
+ def association
60
+ model.associations.first_where(from_key_name: name)
61
+ end
62
+
63
+ def null?
64
+ column_definition.null
65
+ end
51
66
  end
52
- end
67
+ end
data/lib/traits/base.rb CHANGED
@@ -1,7 +1,10 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Base
3
6
  def to_hash
4
7
  {}
5
8
  end
6
9
  end
7
- end
10
+ end
@@ -1,27 +1,31 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  module DescendantsListing
3
6
  def active_record_descendants_loaded?
4
- !!@ar_descendants
7
+ !!@ar_descendants_loaded
5
8
  end
6
9
 
7
10
  def load_active_record_descendants!
8
- # Railties are not necessary here
9
- # Source: http://stackoverflow.com/questions/6497834/differences-between-railties-and-engines-in-ruby-on-rails-3
10
- Rails::Engine.subclasses.map(&:instance).each { |i| i.eager_load! }
11
- Rails.application.eager_load!
11
+ @ar_descendants_loaded ||= begin
12
+ # Railties are not necessary here
13
+ # Source: http://stackoverflow.com/questions/6497834/differences-between-railties-and-engines-in-ruby-on-rails-3
14
+ Rails::Engine.subclasses.map(&:instance).each { |i| i.eager_load! }
15
+ Rails.application.eager_load!
16
+ true
17
+ end
12
18
  end
13
19
 
14
20
  def invalidate_loaded_active_record_descendants!
15
- @ar_descendants = nil
21
+ @ar_descendants = nil
22
+ @ar_descendants_loaded = false
16
23
  end
17
24
 
18
25
  def active_record_descendants
19
26
  @ar_descendants ||= begin
20
27
  load_active_record_descendants!
21
- descendants = ActiveRecord::Base.descendants
22
-
23
- descendants.reject! { |ar| excluded_active_record_descendant?(ar) }
24
- descendants
28
+ ActiveRecord::Base.descendants.reject! { |ar| excluded_active_record_descendant?(ar) }
25
29
  end
26
30
  end
27
31
 
@@ -48,4 +52,4 @@ module Traits
48
52
  /\AHABTM/,
49
53
  /::Translation\Z/
50
54
  ]
51
- end
55
+ end
data/lib/traits/list.rb CHANGED
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class List
3
6
  include Enumerable
@@ -7,28 +10,14 @@ module Traits
7
10
  end
8
11
 
9
12
  def filter(hash)
10
- select do |attr|
11
- hash.all? do |method, expected|
12
- returned = attr.send(method)
13
- if expected.is_a?(Array)
14
- expected.include?(returned)
15
- else
16
- returned == expected
17
- end
18
- end
13
+ select do |item|
14
+ hash.all? { |method, expected| compare(item, method, expected) }
19
15
  end
20
16
  end
21
17
 
22
18
  def first_where(hash)
23
- find do |attr|
24
- hash.all? do |method, expected|
25
- returned = attr.send(method)
26
- if expected.is_a?(Array)
27
- expected.include?(returned)
28
- else
29
- returned == expected
30
- end
31
- end
19
+ find do |item|
20
+ hash.all? { |method, expected| compare(item, method, expected) }
32
21
  end
33
22
  end
34
23
 
@@ -41,12 +30,28 @@ module Traits
41
30
  end
42
31
 
43
32
  def by_name(name)
44
- name = name.to_s.to_sym
33
+ name = name.to_sym if name.kind_of?(String)
45
34
  find { |attr| attr.name == name }
46
35
  end
47
36
 
48
37
  def to_hash
49
38
  each_with_object({}) { |item, memo| memo[item.name] = item.to_hash }
50
39
  end
40
+
41
+ protected
42
+ def compare(item, method, expected)
43
+ returned = item.send(method)
44
+ case expected
45
+ when Array then expected.include?(returned)
46
+ when Regexp then returned =~ expected
47
+ else returned == expected
48
+ end
49
+ end
50
+ end
51
+
52
+ class AttributeList < List
53
+ def primary_key
54
+ first_where(primary_key?: true)
55
+ end
51
56
  end
52
- end
57
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Model
3
6
  module EssayShortcuts
@@ -6,4 +9,4 @@ module Traits
6
9
  end
7
10
  end
8
11
  end
9
- end
12
+ end
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Traits
5
+ class Model
6
+ module Inheritance
7
+ def uses_inheritance?
8
+ inheritance_base? || inheritance_derived?
9
+ end
10
+ alias uses_sti? uses_inheritance?
11
+
12
+ def inheritance_base?
13
+ model_class.descends_from_active_record? &&
14
+ !model_class.abstract_class? &&
15
+ model_class.subclasses.any? { |subclass| subclass.superclass == model_class }
16
+ end
17
+ alias sti_base? inheritance_base?
18
+
19
+ def inheritance_derived?
20
+ !model_class.descends_from_active_record?
21
+ end
22
+ alias sti_derived? inheritance_derived?
23
+
24
+ def inheritance_attribute
25
+ attributes[model_class.inheritance_column]
26
+ end
27
+ alias sti_attribute inheritance_attribute
28
+
29
+ def inheritance_attribute_name
30
+ inheritance_attribute.name if uses_inheritance?
31
+ end
32
+ alias sti_attribute_name inheritance_attribute_name
33
+
34
+ # class File < ActiveRecord::Base
35
+ # end
36
+ #
37
+ # class Photo < File
38
+ # end
39
+ #
40
+ # class Video < File
41
+ # end
42
+ #
43
+ # class Portrait < Photo
44
+ # end
45
+ #
46
+ # File.traits.inheritance_chain => [File]
47
+ # Photo.traits.inheritance_chain => [File, Photo]
48
+ # Video.traits.inheritance_chain => [File, Video]
49
+ # Portrait.traits.inheritance_chain => [File, Photo, Portrait]
50
+ def inheritance_chain
51
+ Traits.load_active_record_descendants!
52
+ model_class = self.model_class
53
+ chain = [model_class]
54
+ until model_class.superclass == ActiveRecord::Base do
55
+ model_class = model_class.superclass
56
+ chain.unshift(model_class)
57
+ end
58
+ chain
59
+ end
60
+ alias sti_chain inheritance_chain
61
+
62
+ def inheritance_base
63
+ inheritance_chain[0]
64
+ end
65
+
66
+ def to_hash
67
+ super.merge!(
68
+ is_sti_base: sti_base?,
69
+ is_sti_derived: sti_derived?,
70
+ sti_attribute_name: sti_attribute_name,
71
+ sti_chain: sti_chain.map { |model_class| model_class.traits.name }
72
+ )
73
+ end
74
+ end
75
+ end
76
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Model
3
6
  module Naming
@@ -66,7 +69,9 @@ module Traits
66
69
  # lookup_name(:underscore) => assets_photo
67
70
  #
68
71
  def lookup_name(namecase = :class)
69
- namecase == :underscore ? name.gsub('/', '_') : class_name.gsub('::', '')
72
+ namecase == :underscore ?
73
+ @lookup_name_underscore_case ||= name.gsub('/', '_') :
74
+ @lookup_name_class_case ||= class_name.gsub('::', '')
70
75
  end
71
76
 
72
77
  def to_hash
@@ -80,4 +85,4 @@ module Traits
80
85
  end
81
86
  end
82
87
  end
83
- end
88
+ end
@@ -1,8 +1,11 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Model
3
6
  module Polymorphism
4
7
  def polymorphic_type
5
- model_class.base_class.name.to_sym
8
+ @polymorphic_type ||= model_class.base_class.name.to_sym
6
9
  end
7
10
 
8
11
  def to_hash
@@ -12,4 +15,4 @@ module Traits
12
15
  end
13
16
  end
14
17
  end
15
- end
18
+ end
@@ -1,8 +1,20 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Model
3
6
  module Querying
4
7
  def primary_key_name
5
- model_class.primary_key.to_sym
8
+ # Sometimes table doesn't have primary key.
9
+ # This might be many-to-many tables (HABTM).
10
+ @pk_name ||= begin
11
+ pk = model_class.primary_key
12
+ pk.kind_of?(String) ? pk.to_sym : pk
13
+ end
14
+ end
15
+
16
+ def primary_key_attribute
17
+ @pk_attr ||= attributes[primary_key_name]
6
18
  end
7
19
 
8
20
  def arel
@@ -14,11 +26,11 @@ module Traits
14
26
  end
15
27
 
16
28
  def table_name
17
- model_class.table_name
29
+ @table_name ||= model_class.table_name
18
30
  end
19
31
 
20
32
  def quoted_table_name
21
- connection.quote_table_name(model_class.table_name)
33
+ @quote_table_name ||= connection.quote_table_name(model_class.table_name)
22
34
  end
23
35
 
24
36
  def to_hash
@@ -31,4 +43,4 @@ module Traits
31
43
  end
32
44
  end
33
45
  end
34
- end
46
+ end
data/lib/traits/model.rb CHANGED
@@ -1,18 +1,21 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class Model < Base
3
6
  end
4
7
  end
5
8
 
6
- require 'traits/concerns/model/naming'
7
- require 'traits/concerns/model/polymorphism'
8
- require 'traits/concerns/model/sti'
9
- require 'traits/concerns/model/querying'
10
- require 'traits/concerns/model/essay_shortcuts'
9
+ require 'traits/model/naming'
10
+ require 'traits/model/polymorphism'
11
+ require 'traits/model/inheritance'
12
+ require 'traits/model/querying'
13
+ require 'traits/model/essay_shortcuts'
11
14
 
12
15
  module Traits
13
16
  class Model
14
17
  include Naming
15
- include STI
18
+ include Inheritance
16
19
  include Polymorphism
17
20
  include Querying
18
21
  include EssayShortcuts
@@ -45,34 +48,47 @@ module Traits
45
48
  )
46
49
  end
47
50
 
51
+ def descendants
52
+ Traits.load_active_record_descendants!
53
+ active_record.descendants
54
+ end
55
+
48
56
  protected
49
57
 
50
58
  # TODO Store, Storage, Virtual attributes
51
59
  def inspect_attributes
52
- columns = model_class.columns_hash.values
53
-
54
- if features.translates_with_globalize?
55
- globalize = features.globalize
56
- tr_class = globalize.model_class_for_translations
57
- tr_columns_hash = tr_class.columns_hash
60
+ if model_class.abstract_class?
61
+ Traits::AttributeList.new([])
62
+ else
63
+ columns = model_class.columns_hash.values
64
+
65
+ if features.translates_with_globalize?
66
+ globalize = features.globalize
67
+ tr_class = globalize.model_class_for_translations
68
+ tr_columns_hash = tr_class.columns_hash
69
+
70
+ columns += globalize.translated_attribute_names.map do |el|
71
+ tr_columns_hash[el.to_s]
72
+ end
73
+ end
58
74
 
59
- columns += globalize.translated_attribute_names.map do |el|
60
- tr_columns_hash[el.to_s]
75
+ list = columns.map do |column|
76
+ Traits::Attribute.new(model_class, column)
61
77
  end
62
- end
63
78
 
64
- list = columns.map do |column|
65
- Traits::Attribute.new(model_class, column)
79
+ Traits::AttributeList.new(list)
66
80
  end
67
-
68
- Traits::List.new(list)
69
81
  end
70
82
 
71
83
  def inspect_associations
72
- list = model_class.reflections.map do |pair|
73
- Traits::Association.new(model_class, pair.last)
84
+ if model_class.abstract_class?
85
+ Traits::List.new([])
86
+ else
87
+ list = model_class.reflections.map do |pair|
88
+ Traits::Association.new(model_class, pair.last)
89
+ end
90
+ Traits::List.new(list)
74
91
  end
75
- Traits::List.new(list)
76
92
  end
77
93
  end
78
- end
94
+ end
@@ -1,8 +1,9 @@
1
- module Traits
2
- class Engine < Rails::Engine
3
- isolate_namespace Traits
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
4
3
 
5
- config.before_initialize do |app|
4
+ module Traits
5
+ class Railtie < Rails::Railtie
6
+ initializer do |app|
6
7
  unless app.config.cache_classes
7
8
  ActionDispatch::Reloader.to_prepare do
8
9
  Traits.invalidate_loaded_active_record_descendants!
@@ -10,4 +11,4 @@ module Traits
10
11
  end
11
12
  end
12
13
  end
13
- end
14
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
5
  class UnidentifiedModelReference < StandardError
3
6
  end
@@ -34,4 +37,4 @@ module Traits
34
37
  end
35
38
 
36
39
  extend Utilities
37
- end
40
+ end
@@ -1,3 +1,6 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
1
4
  module Traits
2
- VERSION = '1.0.0'
3
- end
5
+ VERSION = '1.0.1'
6
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-traits
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yaroslav Konoplov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-04 00:00:00.000000000 Z
11
+ date: 2016-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,73 +16,44 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 3.2.0
19
+ version: '3.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '6.0'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: 3.2.0
29
+ version: '3.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '6.0'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: activerecord
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
37
  - - ">="
32
38
  - !ruby/object:Gem::Version
33
- version: 3.2.0
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
+ version: '3.0'
40
+ - - "<"
39
41
  - !ruby/object:Gem::Version
40
- version: 3.2.0
41
- - !ruby/object:Gem::Dependency
42
- name: essay
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: 1.0.0
42
+ version: '6.0'
48
43
  type: :runtime
49
44
  prerelease: false
50
45
  version_requirements: !ruby/object:Gem::Requirement
51
46
  requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: 1.0.0
55
- - !ruby/object:Gem::Dependency
56
- name: essay-globalize
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 1.0.0
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 1.0.0
69
- - !ruby/object:Gem::Dependency
70
- name: essay-carrierwave
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
47
+ - - ">="
74
48
  - !ruby/object:Gem::Version
75
- version: 1.0.0
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
49
+ version: '3.0'
50
+ - - "<"
81
51
  - !ruby/object:Gem::Version
82
- version: 1.0.0
83
- description: Type information of ActiveRecord models, attributes and associations
52
+ version: '6.0'
53
+ description: Type information of activerecord models, attributes and associations
54
+ in good and clear manner
84
55
  email:
85
- - yaroslav@inbox.com
56
+ - eahome00@gmail.com
86
57
  executables: []
87
58
  extensions: []
88
59
  extra_rdoc_files: []
@@ -91,37 +62,36 @@ files:
91
62
  - Gemfile
92
63
  - LICENSE.txt
93
64
  - README.md
94
- - Rakefile
95
65
  - activerecord-traits.gemspec
96
66
  - lib/activerecord-traits.rb
97
67
  - lib/traits/association.rb
68
+ - lib/traits/association/essay_shortcuts.rb
69
+ - lib/traits/association/intermediate.rb
70
+ - lib/traits/association/join.rb
71
+ - lib/traits/association/macro.rb
72
+ - lib/traits/association/members.rb
73
+ - lib/traits/association/naming.rb
74
+ - lib/traits/association/polymorphism.rb
75
+ - lib/traits/association/read_only.rb
76
+ - lib/traits/association/through.rb
98
77
  - lib/traits/attribute.rb
78
+ - lib/traits/attribute/essay_shortcuts.rb
79
+ - lib/traits/attribute/inheritance.rb
80
+ - lib/traits/attribute/key.rb
81
+ - lib/traits/attribute/naming.rb
82
+ - lib/traits/attribute/polymorphism.rb
83
+ - lib/traits/attribute/querying.rb
84
+ - lib/traits/attribute/type.rb
99
85
  - lib/traits/base.rb
100
- - lib/traits/concerns/association/essay_shortcuts.rb
101
- - lib/traits/concerns/association/intermediate.rb
102
- - lib/traits/concerns/association/join.rb
103
- - lib/traits/concerns/association/macro.rb
104
- - lib/traits/concerns/association/members.rb
105
- - lib/traits/concerns/association/naming.rb
106
- - lib/traits/concerns/association/polymorphism.rb
107
- - lib/traits/concerns/association/read_only.rb
108
- - lib/traits/concerns/association/through.rb
109
- - lib/traits/concerns/attribute/essay_shortcuts.rb
110
- - lib/traits/concerns/attribute/key.rb
111
- - lib/traits/concerns/attribute/naming.rb
112
- - lib/traits/concerns/attribute/polymorphism.rb
113
- - lib/traits/concerns/attribute/querying.rb
114
- - lib/traits/concerns/attribute/sti.rb
115
- - lib/traits/concerns/attribute/type.rb
116
- - lib/traits/concerns/model/essay_shortcuts.rb
117
- - lib/traits/concerns/model/naming.rb
118
- - lib/traits/concerns/model/polymorphism.rb
119
- - lib/traits/concerns/model/querying.rb
120
- - lib/traits/concerns/model/sti.rb
121
86
  - lib/traits/descendants_listing.rb
122
- - lib/traits/engine.rb
123
87
  - lib/traits/list.rb
124
88
  - lib/traits/model.rb
89
+ - lib/traits/model/essay_shortcuts.rb
90
+ - lib/traits/model/inheritance.rb
91
+ - lib/traits/model/naming.rb
92
+ - lib/traits/model/polymorphism.rb
93
+ - lib/traits/model/querying.rb
94
+ - lib/traits/railtie.rb
125
95
  - lib/traits/utilities.rb
126
96
  - lib/traits/version.rb
127
97
  homepage: http://github.com/yivo/activerecord-traits
@@ -144,8 +114,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
144
114
  version: '0'
145
115
  requirements: []
146
116
  rubyforge_project:
147
- rubygems_version: 2.4.8
117
+ rubygems_version: 2.5.1
148
118
  signing_key:
149
119
  specification_version: 4
150
- summary: Type information of ActiveRecord models, attributes and associations
120
+ summary: Type information of activerecord models
151
121
  test_files: []
data/Rakefile DELETED
@@ -1 +0,0 @@
1
- require 'bundler/gem_tasks'
@@ -1,15 +0,0 @@
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
@@ -1,41 +0,0 @@
1
- module Traits
2
- class Model
3
- module STI
4
- def uses_sti?
5
- sti_base? || sti_derived?
6
- end
7
-
8
- def sti_base?
9
- model_class.descends_from_active_record? && model_class.subclasses.any? do |subclass|
10
- subclass.superclass == model_class
11
- end
12
- end
13
-
14
- def sti_derived?
15
- !model_class.descends_from_active_record?
16
- end
17
-
18
- def sti_attribute_name
19
- model_class.inheritance_column.to_sym
20
- end
21
-
22
- def sti_chain
23
- model_class = self.model_class
24
- chain = [model_class]
25
- until model_class.superclass == ActiveRecord::Base do
26
- model_class = model_class.superclass
27
- chain.unshift(model_class)
28
- end
29
- chain
30
- end
31
-
32
- def to_hash
33
- super.merge!(
34
- sti_base: sti_base?,
35
- sti_derived: sti_derived?,
36
- sti_attribute_name: sti_attribute_name
37
- )
38
- end
39
- end
40
- end
41
- end