activerecord-traits 1.0.0 → 1.0.1

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