all_futures 1.0.3 → 2.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.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +4 -1
  3. data/Gemfile.lock +272 -61
  4. data/LICENSE.txt +1 -1
  5. data/README.md +59 -79
  6. data/Rakefile +13 -1
  7. data/SUMMARY.md +22 -2
  8. data/bin/console +8 -0
  9. data/bin/loc +0 -0
  10. data/bin/setup +0 -0
  11. data/bin/standardize +0 -0
  12. data/lib/all_futures/association.rb +42 -0
  13. data/lib/all_futures/association_index.rb +69 -0
  14. data/lib/all_futures/attributes.rb +28 -0
  15. data/lib/all_futures/base.rb +66 -0
  16. data/lib/all_futures/callbacks.rb +71 -0
  17. data/lib/all_futures/configuration.rb +9 -0
  18. data/lib/all_futures/dirty.rb +116 -0
  19. data/lib/all_futures/embeds.rb +40 -0
  20. data/lib/all_futures/errors.rb +37 -0
  21. data/lib/all_futures/finder.rb +214 -0
  22. data/lib/all_futures/locale/en.yml +49 -0
  23. data/lib/all_futures/persistence.rb +595 -0
  24. data/lib/all_futures/presenter.rb +35 -0
  25. data/lib/all_futures/railtie.rb +26 -0
  26. data/lib/all_futures/translation.rb +22 -0
  27. data/lib/all_futures/validations.rb +10 -0
  28. data/lib/all_futures/version.rb +3 -1
  29. data/lib/all_futures/versions.rb +80 -0
  30. data/lib/all_futures.rb +24 -1
  31. data/lib/vendor/ACTIVE_ENTITY_MIT-LICENSE +42 -0
  32. data/lib/vendor/README.md +8 -0
  33. data/lib/vendor/active_entity/aggregations.rb +277 -0
  34. data/lib/vendor/active_entity/associations/embeds/association.rb +134 -0
  35. data/lib/vendor/active_entity/associations/embeds/builder/association.rb +105 -0
  36. data/lib/vendor/active_entity/associations/embeds/builder/collection_association.rb +71 -0
  37. data/lib/vendor/active_entity/associations/embeds/builder/embedded_in.rb +38 -0
  38. data/lib/vendor/active_entity/associations/embeds/builder/embeds_many.rb +13 -0
  39. data/lib/vendor/active_entity/associations/embeds/builder/embeds_one.rb +16 -0
  40. data/lib/vendor/active_entity/associations/embeds/builder/singular_association.rb +28 -0
  41. data/lib/vendor/active_entity/associations/embeds/collection_association.rb +209 -0
  42. data/lib/vendor/active_entity/associations/embeds/collection_proxy.rb +310 -0
  43. data/lib/vendor/active_entity/associations/embeds/embedded_in_association.rb +31 -0
  44. data/lib/vendor/active_entity/associations/embeds/embeds_many_association.rb +15 -0
  45. data/lib/vendor/active_entity/associations/embeds/embeds_one_association.rb +26 -0
  46. data/lib/vendor/active_entity/associations/embeds/singular_association.rb +35 -0
  47. data/lib/vendor/active_entity/associations.rb +168 -0
  48. data/lib/vendor/active_entity/attribute_assignment.rb +87 -0
  49. data/lib/vendor/active_entity/attribute_decorators.rb +90 -0
  50. data/lib/vendor/active_entity/attribute_methods/before_type_cast.rb +78 -0
  51. data/lib/vendor/active_entity/attribute_methods/dirty.rb +180 -0
  52. data/lib/vendor/active_entity/attribute_methods/primary_key.rb +96 -0
  53. data/lib/vendor/active_entity/attribute_methods/query.rb +38 -0
  54. data/lib/vendor/active_entity/attribute_methods/read.rb +44 -0
  55. data/lib/vendor/active_entity/attribute_methods/serialization.rb +90 -0
  56. data/lib/vendor/active_entity/attribute_methods/time_zone_conversion.rb +93 -0
  57. data/lib/vendor/active_entity/attribute_methods/write.rb +54 -0
  58. data/lib/vendor/active_entity/attribute_methods.rb +833 -0
  59. data/lib/vendor/active_entity/attributes.rb +240 -0
  60. data/lib/vendor/active_entity/base.rb +293 -0
  61. data/lib/vendor/active_entity/callbacks.rb +21 -0
  62. data/lib/vendor/active_entity/coders/json.rb +15 -0
  63. data/lib/vendor/active_entity/coders/yaml_column.rb +50 -0
  64. data/lib/vendor/active_entity/core.rb +348 -0
  65. data/lib/vendor/active_entity/enum.rb +260 -0
  66. data/lib/vendor/active_entity/errors.rb +69 -0
  67. data/lib/vendor/active_entity/gem_version.rb +17 -0
  68. data/lib/vendor/active_entity/inheritance.rb +176 -0
  69. data/lib/vendor/active_entity/integration.rb +78 -0
  70. data/lib/vendor/active_entity/locale/en.yml +45 -0
  71. data/lib/vendor/active_entity/model_schema.rb +118 -0
  72. data/lib/vendor/active_entity/nested_attributes.rb +554 -0
  73. data/lib/vendor/active_entity/persistence.rb +20 -0
  74. data/lib/vendor/active_entity/railtie.rb +76 -0
  75. data/lib/vendor/active_entity/readonly_attributes.rb +55 -0
  76. data/lib/vendor/active_entity/reflection.rb +447 -0
  77. data/lib/vendor/active_entity/serialization.rb +28 -0
  78. data/lib/vendor/active_entity/store.rb +291 -0
  79. data/lib/vendor/active_entity/translation.rb +24 -0
  80. data/lib/vendor/active_entity/type/date.rb +9 -0
  81. data/lib/vendor/active_entity/type/date_time.rb +9 -0
  82. data/lib/vendor/active_entity/type/internal/timezone.rb +17 -0
  83. data/lib/vendor/active_entity/type/json.rb +30 -0
  84. data/lib/vendor/active_entity/type/modifiers/array.rb +72 -0
  85. data/lib/vendor/active_entity/type/modifiers/array_without_blank.rb +19 -0
  86. data/lib/vendor/active_entity/type/registry.rb +112 -0
  87. data/lib/vendor/active_entity/type/serialized.rb +71 -0
  88. data/lib/vendor/active_entity/type/text.rb +11 -0
  89. data/lib/vendor/active_entity/type/time.rb +21 -0
  90. data/lib/vendor/active_entity/type/unsigned_integer.rb +17 -0
  91. data/lib/vendor/active_entity/type.rb +75 -0
  92. data/lib/vendor/active_entity/validate_embeds_association.rb +300 -0
  93. data/lib/vendor/active_entity/validations/absence.rb +25 -0
  94. data/lib/vendor/active_entity/validations/associated.rb +60 -0
  95. data/lib/vendor/active_entity/validations/length.rb +26 -0
  96. data/lib/vendor/active_entity/validations/presence.rb +68 -0
  97. data/lib/vendor/active_entity/validations/subset.rb +76 -0
  98. data/lib/vendor/active_entity/validations/uniqueness_in_embeds.rb +91 -0
  99. data/lib/vendor/active_entity/validations/uniqueness_on_active_record.rb +234 -0
  100. data/lib/vendor/active_entity/validations.rb +47 -0
  101. data/lib/vendor/active_entity/version.rb +10 -0
  102. data/lib/vendor/active_entity.rb +99 -0
  103. data/lib/vendor/core_ext/array_without_blank.rb +48 -0
  104. metadata +175 -21
  105. data/lib/all_futures/all_futures.rb +0 -28
  106. data/lib/all_futures/config.rb +0 -14
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/indifferent_access"
4
+
5
+ module ActiveEntity
6
+ # == Single table inheritance
7
+ #
8
+ # Active Entity allows inheritance by storing the name of the class in a column that by
9
+ # default is named "type" (can be changed by overwriting <tt>Base.inheritance_column</tt>).
10
+ # This means that an inheritance looking like this:
11
+ #
12
+ # class Company < ActiveEntity::Base; end
13
+ # class Firm < Company; end
14
+ # class Client < Company; end
15
+ # class PriorityClient < Client; end
16
+ #
17
+ # When you do <tt>Firm.create(name: "37signals")</tt>, this record will be saved in
18
+ # the companies table with type = "Firm". You can then fetch this row again using
19
+ # <tt>Company.where(name: '37signals').first</tt> and it will return a Firm object.
20
+ #
21
+ # Be aware that because the type column is an attribute on the record every new
22
+ # subclass will instantly be marked as dirty and the type column will be included
23
+ # in the list of changed attributes on the record. This is different from non
24
+ # Single Table Inheritance(STI) classes:
25
+ #
26
+ # Company.new.changed? # => false
27
+ # Firm.new.changed? # => true
28
+ # Firm.new.changes # => {"type"=>["","Firm"]}
29
+ #
30
+ # If you don't have a type column defined in your table, single-table inheritance won't
31
+ # be triggered. In that case, it'll work just like normal subclasses with no special magic
32
+ # for differentiating between them or reloading the right type with find.
33
+ #
34
+ # Note, all the attributes for all the cases are kept in the same table. Read more:
35
+ # https://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
36
+ #
37
+ module Inheritance
38
+ extend ActiveSupport::Concern
39
+
40
+ module ClassMethods
41
+ # Determines if one of the attributes passed in is the inheritance column,
42
+ # and if the inheritance column is attr accessible, it initializes an
43
+ # instance of the given subclass instead of the base class.
44
+ def new(attributes = nil, &block)
45
+ if abstract_class? || self == Base
46
+ raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
47
+ end
48
+
49
+ super
50
+ end
51
+
52
+ # Returns +true+ if this does not need STI type condition. Returns
53
+ # +false+ if STI type condition needs to be applied.
54
+ def descends_from_active_entity?
55
+ if self == Base
56
+ false
57
+ elsif superclass.abstract_class?
58
+ superclass.descends_from_active_entity?
59
+ else
60
+ superclass == Base
61
+ end
62
+ end
63
+
64
+ # Returns the class descending directly from ActiveEntity::Base, or
65
+ # an abstract class, if any, in the inheritance hierarchy.
66
+ #
67
+ # If A extends ActiveEntity::Base, A.base_class will return A. If B descends from A
68
+ # through some arbitrarily deep hierarchy, B.base_class will return A.
69
+ #
70
+ # If B < A and C < B and if A is an abstract_class then both B.base_class
71
+ # and C.base_class would return B as the answer since A is an abstract_class.
72
+ def base_class
73
+ unless self < Base
74
+ raise ActiveEntityError, "#{name} doesn't belong in a hierarchy descending from ActiveEntity"
75
+ end
76
+
77
+ if superclass == Base || superclass.abstract_class?
78
+ self
79
+ else
80
+ superclass.base_class
81
+ end
82
+ end
83
+
84
+ # Returns whether the class is a base class.
85
+ # See #base_class for more information.
86
+ def base_class?
87
+ base_class == self
88
+ end
89
+
90
+ # Set this to +true+ if this is an abstract class (see
91
+ # <tt>abstract_class?</tt>).
92
+ # If you are using inheritance with Active Entity and don't want a class
93
+ # to be considered as part of the STI hierarchy, you must set this to
94
+ # true.
95
+ # +ApplicationRecord+, for example, is generated as an abstract class.
96
+ #
97
+ # Consider the following default behaviour:
98
+ #
99
+ # Shape = Class.new(ActiveEntity::Base)
100
+ # Polygon = Class.new(Shape)
101
+ # Square = Class.new(Polygon)
102
+ #
103
+ # Shape.table_name # => "shapes"
104
+ # Polygon.table_name # => "shapes"
105
+ # Square.table_name # => "shapes"
106
+ # Shape.create! # => #<Shape id: 1, type: nil>
107
+ # Polygon.create! # => #<Polygon id: 2, type: "Polygon">
108
+ # Square.create! # => #<Square id: 3, type: "Square">
109
+ #
110
+ # However, when using <tt>abstract_class</tt>, +Shape+ is omitted from
111
+ # the hierarchy:
112
+ #
113
+ # class Shape < ActiveEntity::Base
114
+ # self.abstract_class = true
115
+ # end
116
+ # Polygon = Class.new(Shape)
117
+ # Square = Class.new(Polygon)
118
+ #
119
+ # Shape.table_name # => nil
120
+ # Polygon.table_name # => "polygons"
121
+ # Square.table_name # => "polygons"
122
+ # Shape.create! # => NotImplementedError: Shape is an abstract class and cannot be instantiated.
123
+ # Polygon.create! # => #<Polygon id: 1, type: nil>
124
+ # Square.create! # => #<Square id: 2, type: "Square">
125
+ #
126
+ # Note that in the above example, to disallow the creation of a plain
127
+ # +Polygon+, you should use <tt>validates :type, presence: true</tt>,
128
+ # instead of setting it as an abstract class. This way, +Polygon+ will
129
+ # stay in the hierarchy, and Active Entity will continue to correctly
130
+ # derive the table name.
131
+ attr_accessor :abstract_class
132
+
133
+ # Returns whether this class is an abstract class or not.
134
+ def abstract_class?
135
+ defined?(@abstract_class) && @abstract_class == true
136
+ end
137
+
138
+ def inherited(subclass)
139
+ subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new)
140
+ super
141
+ end
142
+
143
+ protected
144
+
145
+ # Returns the class type of the record using the current module as a prefix. So descendants of
146
+ # MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
147
+ def compute_type(type_name)
148
+ if type_name.start_with?("::")
149
+ # If the type is prefixed with a scope operator then we assume that
150
+ # the type_name is an absolute reference.
151
+ ActiveSupport::Dependencies.constantize(type_name)
152
+ else
153
+ type_candidate = @_type_candidates_cache[type_name]
154
+ if type_candidate && type_constant = type_candidate.safe_constantize
155
+ return type_constant
156
+ end
157
+
158
+ # Build a list of candidates to search for
159
+ candidates = []
160
+ name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" }
161
+ candidates << type_name
162
+
163
+ candidates.each do |candidate|
164
+ constant = candidate.safe_constantize
165
+ if candidate == constant.to_s
166
+ @_type_candidates_cache[type_name] = candidate
167
+ return constant
168
+ end
169
+ end
170
+
171
+ raise NameError.new("uninitialized constant #{candidates.first}", candidates.first)
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/filters"
4
+
5
+ module ActiveEntity
6
+ module Integration
7
+ extend ActiveSupport::Concern
8
+
9
+ # Returns a +String+, which Action Pack uses for constructing a URL to this
10
+ # object. The default implementation returns this record's id as a +String+,
11
+ # or +nil+ if this record's unsaved.
12
+ #
13
+ # For example, suppose that you have a User model, and that you have a
14
+ # <tt>resources :users</tt> route. Normally, +user_path+ will
15
+ # construct a path with the user object's 'id' in it:
16
+ #
17
+ # user = User.find_by(name: 'Phusion')
18
+ # user_path(user) # => "/users/1"
19
+ #
20
+ # You can override +to_param+ in your model to make +user_path+ construct
21
+ # a path using the user's name instead of the user's id:
22
+ #
23
+ # class User < ActiveEntity::Base
24
+ # def to_param # overridden
25
+ # name
26
+ # end
27
+ # end
28
+ #
29
+ # user = User.find_by(name: 'Phusion')
30
+ # user_path(user) # => "/users/Phusion"
31
+ def to_param
32
+ # We can't use alias_method here, because method 'id' optimizes itself on the fly.
33
+ id&.to_s # Be sure to stringify the id for routes
34
+ end
35
+
36
+ module ClassMethods
37
+ # Defines your model's +to_param+ method to generate "pretty" URLs
38
+ # using +method_name+, which can be any attribute or method that
39
+ # responds to +to_s+.
40
+ #
41
+ # class User < ActiveEntity::Base
42
+ # to_param :name
43
+ # end
44
+ #
45
+ # user = User.find_by(name: 'Fancy Pants')
46
+ # user.id # => 123
47
+ # user_path(user) # => "/users/123-fancy-pants"
48
+ #
49
+ # Values longer than 20 characters will be truncated. The value
50
+ # is truncated word by word.
51
+ #
52
+ # user = User.find_by(name: 'David Heinemeier Hansson')
53
+ # user.id # => 125
54
+ # user_path(user) # => "/users/125-david-heinemeier"
55
+ #
56
+ # Because the generated param begins with the record's +id+, it is
57
+ # suitable for passing to +find+. In a controller, for example:
58
+ #
59
+ # params[:id] # => "123-fancy-pants"
60
+ # User.find(params[:id]).id # => 123
61
+ def to_param(method_name = nil)
62
+ if method_name.nil?
63
+ super()
64
+ else
65
+ define_method :to_param do
66
+ if (default = super()) &&
67
+ (result = send(method_name).to_s).present? &&
68
+ (param = result.squish.parameterize.truncate(20, separator: /-/, omission: "")).present?
69
+ "#{default}-#{param}"
70
+ else
71
+ default
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,45 @@
1
+ en:
2
+ # Attributes names common to most models
3
+ #attributes:
4
+ #created_at: "Created at"
5
+ #updated_at: "Updated at"
6
+
7
+ # Default error messages
8
+ errors:
9
+ messages:
10
+ non_subset: "is not subset of the given list"
11
+ duplicated: "duplicated"
12
+
13
+ # Active Entity models configuration
14
+ active_entity:
15
+ errors:
16
+ messages:
17
+ record_invalid: "Validation failed: %{errors}"
18
+ # Append your own errors here or at the model/attributes scope.
19
+
20
+ # You can define own errors for models or model attributes.
21
+ # The values :model, :attribute and :value are always available for interpolation.
22
+ #
23
+ # For example,
24
+ # models:
25
+ # user:
26
+ # blank: "This is a custom blank message for %{model}: %{attribute}"
27
+ # attributes:
28
+ # login:
29
+ # blank: "This is a custom blank message for User login"
30
+ # Will define custom blank validation message for User model and
31
+ # custom blank validation message for login attribute of User model.
32
+ #models:
33
+
34
+ # Translate model names. Used in Model.human_name().
35
+ #models:
36
+ # For example,
37
+ # user: "Dude"
38
+ # will translate User model name to "Dude"
39
+
40
+ # Translate model attribute names. Used in Model.human_attribute_name(attribute).
41
+ #attributes:
42
+ # For example,
43
+ # user:
44
+ # login: "Handle"
45
+ # will translate User attribute "login" as "Handle"
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "monitor"
4
+
5
+ module ActiveEntity
6
+ module ModelSchema
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ delegate :type_for_attribute, to: :class
11
+
12
+ initialize_load_schema_monitor
13
+ end
14
+
15
+ module ClassMethods
16
+ def attributes_builder # :nodoc:
17
+ unless defined?(@attributes_builder) && @attributes_builder
18
+ defaults = _default_attributes
19
+ @attributes_builder = ActiveModel::AttributeSet::Builder.new(attribute_types, defaults)
20
+ end
21
+ @attributes_builder
22
+ end
23
+
24
+ def attribute_types # :nodoc:
25
+ load_schema
26
+ @attribute_types ||= Hash.new(Type.default_value)
27
+ end
28
+
29
+ def yaml_encoder # :nodoc:
30
+ @yaml_encoder ||= ActiveModel::AttributeSet::YAMLEncoder.new(attribute_types)
31
+ end
32
+
33
+ # Returns the type of the attribute with the given name, after applying
34
+ # all modifiers. This method is the only valid source of information for
35
+ # anything related to the types of a model's attributes. This method will
36
+ # access the database and load the model's schema if it is required.
37
+ #
38
+ # The return value of this method will implement the interface described
39
+ # by ActiveModel::Type::Value (though the object itself may not subclass
40
+ # it).
41
+ #
42
+ # +attr_name+ The name of the attribute to retrieve the type for. Must be
43
+ # a string or a symbol.
44
+ def type_for_attribute(attr_name, &block)
45
+ attr_name = attr_name.to_s
46
+ if block
47
+ attribute_types.fetch(attr_name, &block)
48
+ else
49
+ attribute_types[attr_name]
50
+ end
51
+ end
52
+
53
+ def _default_attributes # :nodoc:
54
+ load_schema
55
+ @default_attributes ||= ActiveModel::AttributeSet.new({})
56
+ end
57
+
58
+ protected
59
+
60
+ def initialize_load_schema_monitor
61
+ @load_schema_monitor = Monitor.new
62
+ end
63
+
64
+ private
65
+
66
+ def inherited(child_class)
67
+ super
68
+ child_class.initialize_load_schema_monitor
69
+ end
70
+
71
+ def schema_loaded?
72
+ defined?(@schema_loaded) && @schema_loaded
73
+ end
74
+
75
+ def load_schema
76
+ return if schema_loaded?
77
+ @load_schema_monitor.synchronize do
78
+ return if defined?(@load_schema_invoked) && @load_schema_invoked
79
+
80
+ load_schema!
81
+ @schema_loaded = true
82
+ end
83
+ end
84
+
85
+ def load_schema!
86
+ @load_schema_invoked = true
87
+ end
88
+
89
+ if ActiveSupport::VERSION::MAJOR >= 7
90
+ def reload_schema_from_cache
91
+ @attribute_types = nil
92
+ @default_attributes = nil
93
+ @attributes_builder = nil
94
+ @schema_loaded = false
95
+ @load_schema_invoked = false
96
+ @attribute_names = nil
97
+ @yaml_encoder = nil
98
+ subclasses.each do |descendant|
99
+ descendant.send(:reload_schema_from_cache)
100
+ end
101
+ end
102
+ else
103
+ def reload_schema_from_cache
104
+ @attribute_types = nil
105
+ @default_attributes = nil
106
+ @attributes_builder = nil
107
+ @schema_loaded = false
108
+ @load_schema_invoked = false
109
+ @attribute_names = nil
110
+ @yaml_encoder = nil
111
+ direct_descendants.each do |descendant|
112
+ descendant.send(:reload_schema_from_cache)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end