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,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveEntity
4
+ module Validations
5
+ class UniquenessInEmbedsValidator < ActiveModel::EachValidator # :nodoc:
6
+ ERROR_MESSAGE = "`key` option of the configuration hash must be symbol or array of symbols."
7
+
8
+ def check_validity!
9
+ return if key.is_a?(Symbol) || key.is_a?(Array)
10
+
11
+ raise ArgumentError, ERROR_MESSAGE
12
+ end
13
+
14
+ def validate_each(record, attribute, association_or_value)
15
+ reflection = record.class._reflect_on_association(attribute)
16
+ if reflection
17
+ return unless reflection.is_a?(ActiveEntity::Reflection::EmbeddedAssociationReflection)
18
+ return unless reflection.collection?
19
+ end
20
+
21
+ indexed_attribute =
22
+ if reflection
23
+ reflection.options[:index_errors] || ActiveEntity::Base.index_nested_attribute_errors
24
+ else
25
+ options[:index_errors] || true
26
+ end
27
+
28
+ association_or_value =
29
+ if reflection
30
+ Array.wrap(association_or_value).reject(&:marked_for_destruction?)
31
+ else
32
+ Array.wrap(association_or_value)
33
+ end
34
+
35
+ return if association_or_value.size <= 1
36
+
37
+ duplicate_records =
38
+ if key.is_a? Symbol
39
+ association_or_value.group_by(&key)
40
+ elsif key.is_a? Array
41
+ association_or_value.group_by { |r| key.map { |attr| r.send(attr) } }
42
+ end
43
+ .values
44
+ .select { |v| v.size > 1 }
45
+ .flatten
46
+
47
+ return if duplicate_records.empty?
48
+
49
+ duplicate_records.each do |r|
50
+ if key.is_a? Symbol
51
+ r.errors.add(key, :duplicated, **options)
52
+
53
+ # Hack the record
54
+ normalized_attribute = normalize_attribute(attribute, indexed_attribute, association_or_value.index(r), key)
55
+ record.errors.import r.errors.where(key).first, attribute: normalized_attribute
56
+ elsif key.is_a? Array
57
+ key.each do |attr|
58
+ r.errors.add(attr, :duplicated, **options)
59
+
60
+ # Hack the record
61
+ normalized_attribute = normalize_attribute(attribute, indexed_attribute, association_or_value.index(r), attr)
62
+ record.errors.import r.errors.where(key).first, attribute: normalized_attribute
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def key
71
+ @key ||= options[:key]
72
+ end
73
+
74
+ def normalize_attribute(attribute, indexed_attribute, index, nested_attribute)
75
+ if indexed_attribute
76
+ "#{attribute}[#{index}].#{nested_attribute}"
77
+ else
78
+ "#{attribute}.#{nested_attribute}"
79
+ end
80
+ end
81
+ end
82
+
83
+ module ClassMethods
84
+ # Validates whether the value of the specified attributes are unique
85
+ # in the embedded association.
86
+ def validates_uniqueness_in_embedding_of(*attr_names)
87
+ validates_with UniquenessInEmbeddingValidator, _merge_attributes(attr_names)
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,234 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveEntity
4
+ module Validations
5
+ class UniquenessOnActiveRecordValidator < ActiveModel::EachValidator # :nodoc:
6
+ def initialize(options)
7
+ if options[:conditions] && !options[:conditions].respond_to?(:call)
8
+ raise ArgumentError, "#{options[:conditions]} was passed as :conditions but is not callable. " \
9
+ "Pass a callable instead: `conditions: -> { where(approved: true) }`"
10
+ end
11
+ unless Array(options[:scope]).all? { |scope| scope.respond_to?(:to_sym) }
12
+ raise ArgumentError, "#{options[:scope]} is not supported format for :scope option. " \
13
+ "Pass a symbol or an array of symbols instead: `scope: :user_id`"
14
+ end
15
+ super
16
+
17
+ @klass =
18
+ if options[:class].present?
19
+ options[:class]
20
+ elsif options[:class_name].present?
21
+ options[:class_name].safe_constantize
22
+ else
23
+ nil
24
+ end
25
+
26
+ unless @klass
27
+ raise ArgumentError, "Must provide one of option :class_name or :class."
28
+ end
29
+ unless @klass < ActiveRecord::Base
30
+ raise ArgumentError, "Class must be an Active Entity model, but got #{@klass}."
31
+ end
32
+ if @klass.abstract_class?
33
+ raise ArgumentError, "Class can't be an abstract class."
34
+ end
35
+ end
36
+
37
+ def validate_each(record, attribute, value)
38
+ finder_class = find_finder_class_for(record)
39
+ value = map_enum_attribute(finder_class, attribute, value)
40
+
41
+ relation = build_relation(finder_class, attribute, value)
42
+ relation = scope_relation(record, relation)
43
+ relation = relation.merge(options[:conditions]) if options[:conditions]
44
+
45
+ if relation.exists?
46
+ error_options = options.except(:case_sensitive, :scope, :conditions)
47
+ error_options[:value] = value
48
+
49
+ record.errors.add(attribute, :taken, **error_options)
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ # The check for an existing value should be run from a class that
56
+ # isn't abstract. This means working down from the current class
57
+ # (self), to the first non-abstract class. Since classes don't know
58
+ # their subclasses, we have to build the hierarchy between self and
59
+ # the record's class.
60
+ def find_finder_class_for(record)
61
+ class_hierarchy = [record.class]
62
+
63
+ while class_hierarchy.first != @klass
64
+ class_hierarchy.unshift(class_hierarchy.first.superclass)
65
+ end
66
+
67
+ class_hierarchy.detect { |klass| !klass.abstract_class? }
68
+ end
69
+
70
+ def build_relation(klass, attribute, value)
71
+ relation = klass.unscoped
72
+ comparison = relation.bind_attribute(attribute, value) do |attr, bind|
73
+ return relation.none! if bind.unboundable?
74
+
75
+ if !options.key?(:case_sensitive) || bind.nil?
76
+ klass.connection.default_uniqueness_comparison(attr, bind, klass)
77
+ elsif options[:case_sensitive]
78
+ klass.connection.case_sensitive_comparison(attr, bind)
79
+ else
80
+ # will use SQL LOWER function before comparison, unless it detects a case insensitive collation
81
+ klass.connection.case_insensitive_comparison(attr, bind)
82
+ end
83
+ end
84
+
85
+ relation.where!(comparison)
86
+ end
87
+
88
+ def scope_relation(record, relation)
89
+ Array(options[:scope]).each do |scope_item|
90
+ scope_value = record._read_attribute(scope_item)
91
+ relation = relation.where(scope_item => scope_value)
92
+ end
93
+
94
+ relation
95
+ end
96
+
97
+ def map_enum_attribute(klass, attribute, value)
98
+ mapping = klass.defined_enums[attribute.to_s]
99
+ value = mapping[value] if value && mapping
100
+ value
101
+ end
102
+ end
103
+
104
+ module ClassMethods
105
+ # Validates whether the value of the specified attributes are unique
106
+ # across the system. Useful for making sure that only one user
107
+ # can be named "davidhh".
108
+ #
109
+ # class Person < ActiveEntity::Base
110
+ # validates_uniqueness_of :user_name
111
+ # end
112
+ #
113
+ # It can also validate whether the value of the specified attributes are
114
+ # unique based on a <tt>:scope</tt> parameter:
115
+ #
116
+ # class Person < ActiveEntity::Base
117
+ # validates_uniqueness_of :user_name, scope: :account_id
118
+ # end
119
+ #
120
+ # Or even multiple scope parameters. For example, making sure that a
121
+ # teacher can only be on the schedule once per semester for a particular
122
+ # class.
123
+ #
124
+ # class TeacherSchedule < ActiveEntity::Base
125
+ # validates_uniqueness_of :teacher_id, scope: [:semester_id, :class_id]
126
+ # end
127
+ #
128
+ # It is also possible to limit the uniqueness constraint to a set of
129
+ # records matching certain conditions. In this example archived articles
130
+ # are not being taken into consideration when validating uniqueness
131
+ # of the title attribute:
132
+ #
133
+ # class Article < ActiveEntity::Base
134
+ # validates_uniqueness_of :title, conditions: -> { where.not(status: 'archived') }
135
+ # end
136
+ #
137
+ # When the record is created, a check is performed to make sure that no
138
+ # record exists in the database with the given value for the specified
139
+ # attribute (that maps to a column). When the record is updated,
140
+ # the same check is made but disregarding the record itself.
141
+ #
142
+ # Configuration options:
143
+ #
144
+ # * <tt>:message</tt> - Specifies a custom error message (default is:
145
+ # "has already been taken").
146
+ # * <tt>:scope</tt> - One or more columns by which to limit the scope of
147
+ # the uniqueness constraint.
148
+ # * <tt>:conditions</tt> - Specify the conditions to be included as a
149
+ # <tt>WHERE</tt> SQL fragment to limit the uniqueness constraint lookup
150
+ # (e.g. <tt>conditions: -> { where(status: 'active') }</tt>).
151
+ # * <tt>:case_sensitive</tt> - Looks for an exact match. Ignored by
152
+ # non-text columns (+true+ by default).
153
+ # * <tt>:allow_nil</tt> - If set to +true+, skips this validation if the
154
+ # attribute is +nil+ (default is +false+).
155
+ # * <tt>:allow_blank</tt> - If set to +true+, skips this validation if the
156
+ # attribute is blank (default is +false+).
157
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
158
+ # if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
159
+ # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
160
+ # proc or string should return or evaluate to a +true+ or +false+ value.
161
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to
162
+ # determine if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
163
+ # or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The
164
+ # method, proc or string should return or evaluate to a +true+ or +false+
165
+ # value.
166
+ #
167
+ # === Concurrency and integrity
168
+ #
169
+ # Using this validation method in conjunction with
170
+ # {ActiveEntity::Base#save}[rdoc-ref:Persistence#save]
171
+ # does not guarantee the absence of duplicate record insertions, because
172
+ # uniqueness checks on the application level are inherently prone to race
173
+ # conditions. For example, suppose that two users try to post a Comment at
174
+ # the same time, and a Comment's title must be unique. At the database-level,
175
+ # the actions performed by these users could be interleaved in the following manner:
176
+ #
177
+ # User 1 | User 2
178
+ # ------------------------------------+--------------------------------------
179
+ # # User 1 checks whether there's |
180
+ # # already a comment with the title |
181
+ # # 'My Post'. This is not the case. |
182
+ # SELECT * FROM comments |
183
+ # WHERE title = 'My Post' |
184
+ # |
185
+ # | # User 2 does the same thing and also
186
+ # | # infers that their title is unique.
187
+ # | SELECT * FROM comments
188
+ # | WHERE title = 'My Post'
189
+ # |
190
+ # # User 1 inserts their comment. |
191
+ # INSERT INTO comments |
192
+ # (title, content) VALUES |
193
+ # ('My Post', 'hi!') |
194
+ # |
195
+ # | # User 2 does the same thing.
196
+ # | INSERT INTO comments
197
+ # | (title, content) VALUES
198
+ # | ('My Post', 'hello!')
199
+ # |
200
+ # | # ^^^^^^
201
+ # | # Boom! We now have a duplicate
202
+ # | # title!
203
+ #
204
+ # The best way to work around this problem is to add a unique index to the database table using
205
+ # {connection.add_index}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_index].
206
+ # In the rare case that a race condition occurs, the database will guarantee
207
+ # the field's uniqueness.
208
+ #
209
+ # When the database catches such a duplicate insertion,
210
+ # {ActiveEntity::Base#save}[rdoc-ref:Persistence#save] will raise an ActiveEntity::StatementInvalid
211
+ # exception. You can either choose to let this error propagate (which
212
+ # will result in the default Rails exception page being shown), or you
213
+ # can catch it and restart the transaction (e.g. by telling the user
214
+ # that the title already exists, and asking them to re-enter the title).
215
+ # This technique is also known as
216
+ # {optimistic concurrency control}[https://en.wikipedia.org/wiki/Optimistic_concurrency_control].
217
+ #
218
+ # The bundled ActiveEntity::ConnectionAdapters distinguish unique index
219
+ # constraint errors from other types of database errors by throwing an
220
+ # ActiveEntity::RecordNotUnique exception. For other adapters you will
221
+ # have to parse the (database-specific) exception message to detect such
222
+ # a case.
223
+ #
224
+ # The following bundled adapters throw the ActiveEntity::RecordNotUnique exception:
225
+ #
226
+ # * ActiveEntity::ConnectionAdapters::Mysql2Adapter.
227
+ # * ActiveEntity::ConnectionAdapters::SQLite3Adapter.
228
+ # * ActiveEntity::ConnectionAdapters::PostgreSQLAdapter.
229
+ def validates_uniqueness_on_active_record_of(*attr_names)
230
+ validates_with UniquenessOnActiveRecordValidator, _merge_attributes(attr_names)
231
+ end
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveEntity
4
+ # = Active Entity \Validations
5
+ #
6
+ # Active Entity includes the majority of its validations from ActiveModel::Validations
7
+ # all of which accept the <tt>:on</tt> argument to define the context where the
8
+ # validations are active. Active Entity will always supply either the context of
9
+ # <tt>:create</tt> or <tt>:update</tt> dependent on whether the model is a
10
+ # {new_record?}[rdoc-ref:Persistence#new_record?].
11
+ module Validations
12
+ extend ActiveSupport::Concern
13
+ include ActiveModel::Validations
14
+
15
+ # Runs all the validations within the specified context. Returns +true+ if
16
+ # no errors are found, +false+ otherwise.
17
+ #
18
+ # Aliased as #validate.
19
+ #
20
+ # If the argument is +false+ (default is +nil+), the context is set to <tt>:create</tt> if
21
+ # {new_record?}[rdoc-ref:Persistence#new_record?] is +true+, and to <tt>:update</tt> if it is not.
22
+ #
23
+ # \Validations with no <tt>:on</tt> option will run no matter the context. \Validations with
24
+ # some <tt>:on</tt> option will only run in the specified context.
25
+ def valid?(context = nil)
26
+ context ||= :default
27
+ output = super(context)
28
+ errors.empty? && output
29
+ end
30
+
31
+ alias_method :validate, :valid?
32
+
33
+ private
34
+
35
+ def perform_validations(options = {})
36
+ options[:validate] == false || valid?(options[:context])
37
+ end
38
+ end
39
+ end
40
+
41
+ require "active_entity/validations/associated"
42
+ require "active_entity/validations/presence"
43
+ require "active_entity/validations/absence"
44
+ require "active_entity/validations/length"
45
+ require "active_entity/validations/subset"
46
+ require "active_entity/validations/uniqueness_in_embeds"
47
+ require "active_entity/validations/uniqueness_on_active_record"
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "gem_version"
4
+
5
+ module ActiveEntity
6
+ # Returns the version of the currently loaded ActiveEntity as a <tt>Gem::Version</tt>
7
+ def self.version
8
+ gem_version
9
+ end
10
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # Copyright (c) 2004-2020 David Heinemeier Hansson
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ #++
25
+
26
+ require "active_support"
27
+ require "active_support/rails"
28
+ require "active_model"
29
+ require "yaml"
30
+
31
+ require "core_ext/array_without_blank"
32
+
33
+ require "active_entity/version"
34
+ require "active_model/attribute_set"
35
+ require "active_entity/errors"
36
+
37
+ module ActiveEntity
38
+ extend ActiveSupport::Autoload
39
+
40
+ autoload :Base
41
+ autoload :Callbacks
42
+ autoload :Core
43
+ autoload :Enum
44
+ autoload :Inheritance
45
+ autoload :Integration
46
+ autoload :ModelSchema
47
+ autoload :NestedAttributes
48
+ autoload :Persistence
49
+ autoload :ReadonlyAttributes
50
+ autoload :Reflection
51
+ autoload :Serialization
52
+ autoload :Store
53
+ autoload :Translation
54
+ autoload :Validations
55
+
56
+ eager_autoload do
57
+ autoload :Aggregations
58
+ autoload :Associations
59
+ autoload :AttributeAssignment
60
+ autoload :AttributeMethods
61
+ autoload :ValidateEmbedsAssociation
62
+
63
+ autoload :Type
64
+ end
65
+
66
+ module Coders
67
+ autoload :YAMLColumn, "active_entity/coders/yaml_column"
68
+ autoload :JSON, "active_entity/coders/json"
69
+ end
70
+
71
+ module AttributeMethods
72
+ extend ActiveSupport::Autoload
73
+
74
+ eager_autoload do
75
+ autoload :BeforeTypeCast
76
+ autoload :Dirty
77
+ autoload :PrimaryKey
78
+ autoload :Query
79
+ autoload :Read
80
+ autoload :TimeZoneConversion
81
+ autoload :Write
82
+ autoload :Serialization
83
+ end
84
+ end
85
+
86
+ def self.eager_load!
87
+ super
88
+
89
+ ActiveEntity::Associations.eager_load!
90
+ ActiveEntity::AttributeMethods.eager_load!
91
+ end
92
+ end
93
+
94
+ ActiveSupport.on_load(:i18n) do
95
+ I18n.load_path << File.expand_path("active_entity/locale/en.yml", __dir__)
96
+ end
97
+
98
+ YAML.load_tags["!ruby/object:ActiveEntity::AttributeSet"] = "ActiveModel::AttributeSet"
99
+ YAML.load_tags["!ruby/object:ActiveEntity::LazyAttributeHash"] = "ActiveModel::LazyAttributeHash"
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ArrayWithoutBlank < Array
4
+ def self.new(*several_variants)
5
+ arr = super
6
+ arr.reject!(&:blank?)
7
+ arr
8
+ end
9
+
10
+ def initialize_copy(other_ary)
11
+ super other_ary.reject(&:blank?)
12
+ end
13
+
14
+ def replace(other_ary)
15
+ super other_ary.reject(&:blank?)
16
+ end
17
+
18
+ def push(obj, *smth)
19
+ return self if obj.blank?
20
+ super
21
+ end
22
+
23
+ def insert(*args)
24
+ super(*args.reject(&:blank?))
25
+ end
26
+
27
+ def []=(index, obj)
28
+ return self[index] if obj.blank?
29
+ super
30
+ end
31
+
32
+ def concat(other_ary)
33
+ super other_ary.reject(&:blank?)
34
+ end
35
+
36
+ def +(other_ary)
37
+ super other_ary.reject(&:blank?)
38
+ end
39
+
40
+ def <<(obj)
41
+ return self if obj.blank?
42
+ super
43
+ end
44
+
45
+ def to_ary
46
+ Array.new(self)
47
+ end
48
+ end