all_futures 1.0.2 → 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 +297 -0
  4. data/LICENSE.txt +1 -1
  5. data/README.md +59 -77
  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 +172 -31
  105. data/lib/all_futures/all_futures.rb +0 -28
  106. data/lib/all_futures/config.rb +0 -14
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is the parent Association class which defines the variables
4
+ # used by all associations.
5
+ #
6
+ # The hierarchy is defined as follows:
7
+ # Association
8
+ # - SingularAssociation
9
+ # - BelongsToAssociation
10
+ # - HasOneAssociation
11
+ # - CollectionAssociation
12
+ # - HasManyAssociation
13
+
14
+ module ActiveEntity::Associations::Embeds::Builder # :nodoc:
15
+ class Association #:nodoc:
16
+ class << self
17
+ attr_accessor :extensions
18
+ end
19
+ self.extensions = []
20
+
21
+ VALID_OPTIONS = [:class_name, :anonymous_class, :validate] # :nodoc:
22
+
23
+ def self.build(model, name, options)
24
+ if model.dangerous_attribute_method?(name)
25
+ raise ArgumentError, "You tried to define an association named #{name} on the model #{model.name}, but " \
26
+ "this will conflict with a method #{name} already defined by Active Entity. " \
27
+ "Please choose a different association name."
28
+ end
29
+
30
+ reflection = create_reflection model, name, options
31
+ define_accessors model, reflection
32
+ define_callbacks model, reflection
33
+ define_validations model, reflection
34
+ reflection
35
+ end
36
+
37
+ def self.create_reflection(model, name, options, &block)
38
+ raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol)
39
+
40
+ validate_options(options)
41
+
42
+ extension = define_extensions(model, name, &block)
43
+ options[:extend] = [*options[:extend], extension] if extension
44
+
45
+ ActiveEntity::Reflection.create(macro, name, nil, options, model)
46
+ end
47
+
48
+ def self.macro
49
+ raise NotImplementedError
50
+ end
51
+
52
+ def self.valid_options(options)
53
+ VALID_OPTIONS + Association.extensions.flat_map(&:valid_options)
54
+ end
55
+
56
+ def self.validate_options(options)
57
+ options.assert_valid_keys(valid_options(options))
58
+ end
59
+
60
+ def self.define_extensions(model, name)
61
+ end
62
+
63
+ def self.define_callbacks(model, reflection)
64
+ Association.extensions.each do |extension|
65
+ extension.build model, reflection
66
+ end
67
+ end
68
+
69
+ # Defines the setter and getter methods for the association
70
+ # class Post < ActiveEntity::Base
71
+ # has_many :comments
72
+ # end
73
+ #
74
+ # Post.first.comments and Post.first.comments= methods are defined by this method...
75
+ def self.define_accessors(model, reflection)
76
+ mixin = model.generated_association_methods
77
+ name = reflection.name
78
+ define_readers(mixin, name)
79
+ define_writers(mixin, name)
80
+ end
81
+
82
+ def self.define_readers(mixin, name)
83
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
84
+ def #{name}
85
+ association(:#{name}).reader
86
+ end
87
+ CODE
88
+ end
89
+
90
+ def self.define_writers(mixin, name)
91
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
92
+ def #{name}=(value)
93
+ association(:#{name}).writer(value)
94
+ end
95
+ CODE
96
+ end
97
+
98
+ def self.define_validations(_model, _reflection)
99
+ # noop
100
+ end
101
+
102
+ private_class_method :macro, :valid_options, :validate_options, :define_extensions,
103
+ :define_callbacks, :define_accessors, :define_readers, :define_writers, :define_validations
104
+ end
105
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_entity/associations"
4
+
5
+ module ActiveEntity::Associations::Embeds::Builder # :nodoc:
6
+ class CollectionAssociation < Association #:nodoc:
7
+ CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
8
+
9
+ def self.valid_options(options)
10
+ super + [:before_add, :after_add, :before_remove, :after_remove, :extend]
11
+ end
12
+
13
+ def self.define_callbacks(model, reflection)
14
+ super
15
+ name = reflection.name
16
+ options = reflection.options
17
+ CALLBACKS.each { |callback_name|
18
+ define_callback(model, callback_name, name, options)
19
+ }
20
+ end
21
+
22
+ def self.define_extensions(model, name, &block)
23
+ if block_given?
24
+ extension_module_name = "#{name.to_s.camelize}AssociationExtension"
25
+ extension = Module.new(&block)
26
+ model.const_set(extension_module_name, extension)
27
+ end
28
+ end
29
+
30
+ def self.define_callback(model, callback_name, name, options)
31
+ full_callback_name = "#{callback_name}_for_#{name}"
32
+
33
+ # TODO : why do i need method_defined? I think its because of the inheritance chain
34
+ model.class_attribute full_callback_name unless model.method_defined?(full_callback_name)
35
+ callbacks = Array(options[callback_name.to_sym]).map do |callback|
36
+ case callback
37
+ when Symbol
38
+ ->(_method, owner, record) { owner.send(callback, record) }
39
+ when Proc
40
+ ->(_method, owner, record) { callback.call(owner, record) }
41
+ else
42
+ ->(method, owner, record) { callback.send(method, owner, record) }
43
+ end
44
+ end
45
+ model.send "#{full_callback_name}=", callbacks
46
+ end
47
+
48
+ # Defines the setter and getter methods for the collection_singular_ids.
49
+ def self.define_readers(mixin, name)
50
+ super
51
+
52
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
53
+ def #{name.to_s.singularize}_ids
54
+ association(:#{name}).ids_reader
55
+ end
56
+ CODE
57
+ end
58
+
59
+ def self.define_writers(mixin, name)
60
+ super
61
+
62
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
63
+ def #{name.to_s.singularize}_ids=(ids)
64
+ association(:#{name}).ids_writer(ids)
65
+ end
66
+ CODE
67
+ end
68
+
69
+ private_class_method :valid_options, :define_callback, :define_extensions, :define_readers, :define_writers
70
+ end
71
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveEntity::Associations::Embeds::Builder # :nodoc:
4
+ class EmbeddedIn < SingularAssociation #:nodoc:
5
+ def self.macro
6
+ :embedded_in
7
+ end
8
+
9
+ def self.valid_options(options)
10
+ super + [:default]
11
+ end
12
+
13
+ def self.define_callbacks(model, reflection)
14
+ super
15
+ add_default_callbacks(model, reflection) if reflection.options[:default]
16
+ end
17
+
18
+ def self.add_default_callbacks(model, reflection)
19
+ model.before_validation lambda { |o|
20
+ o.association(reflection.name).default(&reflection.options[:default])
21
+ }
22
+ end
23
+
24
+ def self.define_validations(model, reflection)
25
+ if reflection.options.key?(:required)
26
+ reflection.options[:optional] = !reflection.options.delete(:required)
27
+ end
28
+
29
+ required = !reflection.options[:optional]
30
+
31
+ super
32
+
33
+ if required
34
+ model.validates_presence_of reflection.name, message: :required
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveEntity::Associations::Embeds::Builder # :nodoc:
4
+ class EmbedsMany < CollectionAssociation #:nodoc:
5
+ def self.macro
6
+ :embeds_many
7
+ end
8
+
9
+ def self.valid_options(options)
10
+ super + [:inverse_of, :index_errors]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveEntity::Associations::Embeds::Builder # :nodoc:
4
+ class EmbedsOne < SingularAssociation #:nodoc:
5
+ def self.macro
6
+ :embeds_one
7
+ end
8
+
9
+ def self.define_validations(model, reflection)
10
+ super
11
+ if reflection.options[:required]
12
+ model.validates_presence_of reflection.name, message: :required
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class is inherited by the has_one and belongs_to association classes
4
+
5
+ module ActiveEntity::Associations::Embeds::Builder # :nodoc:
6
+ class SingularAssociation < Association #:nodoc:
7
+ def self.valid_options(options)
8
+ super + [:inverse_of, :required]
9
+ end
10
+
11
+ def self.define_accessors(model, reflection)
12
+ super
13
+ mixin = model.generated_association_methods
14
+ name = reflection.name
15
+
16
+ define_constructors(mixin, name) if reflection.constructable?
17
+ end
18
+
19
+ # Defines the (build|create)_association methods for belongs_to or has_one association
20
+ def self.define_constructors(mixin, name)
21
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
22
+ def build_#{name}(*args, &block)
23
+ association(:#{name}).build(*args, &block)
24
+ end
25
+ CODE
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveEntity
4
+ module Associations
5
+ module Embeds
6
+ # = Active Entity Association Collection
7
+ #
8
+ # CollectionAssociation is an abstract class that provides common stuff to
9
+ # ease the implementation of association proxies that represent
10
+ # collections. See the class hierarchy in Association.
11
+ #
12
+ # CollectionAssociation:
13
+ # HasManyAssociation => has_many
14
+ # HasManyThroughAssociation + ThroughAssociation => has_many :through
15
+ #
16
+ # The CollectionAssociation class provides common methods to the collections
17
+ # defined by +has_and_belongs_to_many+, +has_many+ or +has_many+ with
18
+ # the +:through association+ option.
19
+ #
20
+ # You need to be careful with assumptions regarding the target: The proxy
21
+ # does not fetch records from the database until it needs them, but new
22
+ # ones created with +build+ are added to the target. So, the target may be
23
+ # non-empty and still lack children waiting to be read from the database.
24
+ # If you look directly to the database you cannot assume that's the entire
25
+ # collection because new records may have been added to the target, etc.
26
+ #
27
+ # If you need to work on all current children, new and existing records,
28
+ # +load_target+ and the +loaded+ flag are your friends.
29
+ class CollectionAssociation < Association #:nodoc:
30
+ def initialize(owner, reflection)
31
+ super
32
+
33
+ @target = []
34
+ end
35
+
36
+ # Implements the reader method, e.g. foo.items for Foo.has_many :items
37
+ def reader
38
+ @proxy ||= CollectionProxy.new(klass, self)
39
+ end
40
+
41
+ # Implements the writer method, e.g. foo.items= for Foo.has_many :items
42
+ def writer(records)
43
+ replace(records)
44
+ end
45
+
46
+ def find(&block)
47
+ target.find(&block)
48
+ end
49
+
50
+ def build(attributes = {}, &block)
51
+ if attributes.is_a?(Array)
52
+ attributes.collect { |attr| build(attr, &block) }
53
+ else
54
+ add_to_target(build_record(attributes, &block))
55
+ end
56
+ end
57
+
58
+ # Add +records+ to this association. Returns +self+ so method calls may
59
+ # be chained. Since << flattens its argument list and inserts each record,
60
+ # +push+ and +concat+ behave identically.
61
+ def concat(*records)
62
+ records = records.flatten
63
+ concat_records(records)
64
+ end
65
+
66
+ # Removes all records from the association without calling callbacks
67
+ # on the associated records. It honors the +:dependent+ option. However
68
+ # if the +:dependent+ value is +:destroy+ then in that case the +:delete_all+
69
+ # deletion strategy for the association is applied.
70
+ #
71
+ # You can force a particular deletion strategy by passing a parameter.
72
+ #
73
+ # Example:
74
+ #
75
+ # @author.books.delete_all(:nullify)
76
+ # @author.books.delete_all(:delete_all)
77
+ #
78
+ # See delete for more info.
79
+ def delete_all
80
+ target.clear
81
+ end
82
+ alias destroy_all delete_all
83
+
84
+ # Removes +records+ from this association calling +before_remove+ and
85
+ # +after_remove+ callbacks.
86
+ #
87
+ # This method is abstract in the sense that +delete_records+ has to be
88
+ # provided by descendants. Note this method does not imply the records
89
+ # are actually removed from the database, that depends precisely on
90
+ # +delete_records+. They are in any case removed from the collection.
91
+ def delete(*records)
92
+ records.each do |record|
93
+ target.delete(record)
94
+ end
95
+ end
96
+ alias destroy delete
97
+
98
+ # Returns the size of the collection by executing a SELECT COUNT(*)
99
+ # query if the collection hasn't been loaded, and calling
100
+ # <tt>collection.size</tt> if it has.
101
+ #
102
+ # If the collection has been already loaded +size+ and +length+ are
103
+ # equivalent. If not and you are going to need the records anyway
104
+ # +length+ will take one less query. Otherwise +size+ is more efficient.
105
+ #
106
+ # This method is abstract in the sense that it relies on
107
+ # +count_records+, which is a method descendants have to provide.
108
+ def size
109
+ target.size
110
+ end
111
+
112
+ # Returns true if the collection is empty.
113
+ #
114
+ # If the collection has been loaded
115
+ # it is equivalent to <tt>collection.size.zero?</tt>. If the
116
+ # collection has not been loaded, it is equivalent to
117
+ # <tt>collection.exists?</tt>. If the collection has not already been
118
+ # loaded and you are going to fetch the records anyway it is better to
119
+ # check <tt>collection.length.zero?</tt>.
120
+ def empty?
121
+ size.zero?
122
+ end
123
+
124
+ # Replace this collection with +other_array+. This will perform a diff
125
+ # and delete/add only records that have changed.
126
+ def replace(other_array)
127
+ records = other_array.map do |val|
128
+ if val.is_a? reflection.klass
129
+ val
130
+ elsif val.nil?
131
+ next
132
+ elsif val.respond_to?(:to_h)
133
+ build_record(val.to_h)
134
+ end
135
+ rescue => ex
136
+ raise_on_type_mismatch!(val)
137
+ raise ex
138
+ end
139
+
140
+ target.replace records
141
+ end
142
+
143
+ def include?(record)
144
+ if record.is_a?(reflection.klass)
145
+ target.include?(record)
146
+ else
147
+ false
148
+ end
149
+ end
150
+
151
+ def add_to_target(record, skip_callbacks = false, &block)
152
+ # index = @target.index(record)
153
+ # replace_on_target(record, index, skip_callbacks, &block)
154
+ replace_on_target(record, nil, skip_callbacks, &block)
155
+ end
156
+
157
+ private
158
+
159
+ def concat_records(records)
160
+ records.each do |record|
161
+ r =
162
+ if record.is_a? reflection.klass
163
+ record
164
+ elsif record.nil?
165
+ nil
166
+ elsif record.respond_to?(:to_h)
167
+ build_record(record.to_h)
168
+ end
169
+ add_to_target(r)
170
+ rescue => ex
171
+ raise_on_type_mismatch!(record)
172
+ raise ex
173
+ end
174
+
175
+ records
176
+ end
177
+
178
+ def replace_on_target(record, index, skip_callbacks)
179
+ callback(:before_add, record) unless skip_callbacks
180
+
181
+ set_inverse_instance(record)
182
+
183
+ yield(record) if block_given?
184
+
185
+ if index
186
+ target[index] = record
187
+ else
188
+ target << record
189
+ end
190
+
191
+ callback(:after_add, record) unless skip_callbacks
192
+
193
+ record
194
+ end
195
+
196
+ def callback(method, record)
197
+ callbacks_for(method).each do |callback|
198
+ callback.call(method, owner, record)
199
+ end
200
+ end
201
+
202
+ def callbacks_for(callback_name)
203
+ full_callback_name = "#{callback_name}_for_#{reflection.name}"
204
+ owner.class.send(full_callback_name)
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end