active_data 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.rspec +0 -1
  4. data/.rvmrc +1 -1
  5. data/.travis.yml +13 -6
  6. data/Appraisals +7 -0
  7. data/Gemfile +1 -5
  8. data/Guardfile +68 -15
  9. data/README.md +144 -2
  10. data/active_data.gemspec +19 -11
  11. data/gemfiles/rails.4.0.gemfile +14 -0
  12. data/gemfiles/rails.4.1.gemfile +14 -0
  13. data/gemfiles/rails.4.2.gemfile +14 -0
  14. data/gemfiles/rails.5.0.gemfile +14 -0
  15. data/lib/active_data.rb +120 -3
  16. data/lib/active_data/active_record/associations.rb +50 -0
  17. data/lib/active_data/active_record/nested_attributes.rb +24 -0
  18. data/lib/active_data/config.rb +40 -0
  19. data/lib/active_data/errors.rb +93 -0
  20. data/lib/active_data/extensions.rb +33 -0
  21. data/lib/active_data/model.rb +16 -74
  22. data/lib/active_data/model/associations.rb +84 -15
  23. data/lib/active_data/model/associations/base.rb +79 -0
  24. data/lib/active_data/model/associations/collection/embedded.rb +12 -0
  25. data/lib/active_data/model/associations/collection/proxy.rb +32 -0
  26. data/lib/active_data/model/associations/collection/referenced.rb +26 -0
  27. data/lib/active_data/model/associations/embeds_many.rb +124 -18
  28. data/lib/active_data/model/associations/embeds_one.rb +90 -15
  29. data/lib/active_data/model/associations/nested_attributes.rb +180 -0
  30. data/lib/active_data/model/associations/references_many.rb +96 -0
  31. data/lib/active_data/model/associations/references_one.rb +83 -0
  32. data/lib/active_data/model/associations/reflections/base.rb +100 -0
  33. data/lib/active_data/model/associations/reflections/embeds_many.rb +25 -0
  34. data/lib/active_data/model/associations/reflections/embeds_one.rb +49 -0
  35. data/lib/active_data/model/associations/reflections/reference_reflection.rb +45 -0
  36. data/lib/active_data/model/associations/reflections/references_many.rb +28 -0
  37. data/lib/active_data/model/associations/reflections/references_one.rb +28 -0
  38. data/lib/active_data/model/associations/validations.rb +63 -0
  39. data/lib/active_data/model/attributes.rb +247 -0
  40. data/lib/active_data/model/attributes/attribute.rb +73 -0
  41. data/lib/active_data/model/attributes/base.rb +116 -0
  42. data/lib/active_data/model/attributes/collection.rb +17 -0
  43. data/lib/active_data/model/attributes/dictionary.rb +26 -0
  44. data/lib/active_data/model/attributes/localized.rb +42 -0
  45. data/lib/active_data/model/attributes/reference_many.rb +21 -0
  46. data/lib/active_data/model/attributes/reference_one.rb +42 -0
  47. data/lib/active_data/model/attributes/reflections/attribute.rb +55 -0
  48. data/lib/active_data/model/attributes/reflections/base.rb +62 -0
  49. data/lib/active_data/model/attributes/reflections/collection.rb +10 -0
  50. data/lib/active_data/model/attributes/reflections/dictionary.rb +13 -0
  51. data/lib/active_data/model/attributes/reflections/localized.rb +43 -0
  52. data/lib/active_data/model/attributes/reflections/reference_many.rb +10 -0
  53. data/lib/active_data/model/attributes/reflections/reference_one.rb +58 -0
  54. data/lib/active_data/model/attributes/reflections/represents.rb +55 -0
  55. data/lib/active_data/model/attributes/represents.rb +64 -0
  56. data/lib/active_data/model/callbacks.rb +71 -0
  57. data/lib/active_data/model/conventions.rb +35 -0
  58. data/lib/active_data/model/dirty.rb +77 -0
  59. data/lib/active_data/model/lifecycle.rb +307 -0
  60. data/lib/active_data/model/localization.rb +21 -0
  61. data/lib/active_data/model/persistence.rb +57 -0
  62. data/lib/active_data/model/primary.rb +51 -0
  63. data/lib/active_data/model/scopes.rb +77 -0
  64. data/lib/active_data/model/validations.rb +27 -0
  65. data/lib/active_data/model/validations/associated.rb +19 -0
  66. data/lib/active_data/model/validations/nested.rb +39 -0
  67. data/lib/active_data/railtie.rb +7 -0
  68. data/lib/active_data/version.rb +1 -1
  69. data/spec/lib/active_data/active_record/associations_spec.rb +149 -0
  70. data/spec/lib/active_data/active_record/nested_attributes_spec.rb +16 -0
  71. data/spec/lib/active_data/config_spec.rb +44 -0
  72. data/spec/lib/active_data/model/associations/embeds_many_spec.rb +362 -52
  73. data/spec/lib/active_data/model/associations/embeds_one_spec.rb +250 -31
  74. data/spec/lib/active_data/model/associations/nested_attributes_spec.rb +23 -0
  75. data/spec/lib/active_data/model/associations/references_many_spec.rb +196 -0
  76. data/spec/lib/active_data/model/associations/references_one_spec.rb +134 -0
  77. data/spec/lib/active_data/model/associations/reflections/embeds_many_spec.rb +144 -0
  78. data/spec/lib/active_data/model/associations/reflections/embeds_one_spec.rb +116 -0
  79. data/spec/lib/active_data/model/associations/reflections/references_many_spec.rb +255 -0
  80. data/spec/lib/active_data/model/associations/reflections/references_one_spec.rb +208 -0
  81. data/spec/lib/active_data/model/associations/validations_spec.rb +153 -0
  82. data/spec/lib/active_data/model/associations_spec.rb +189 -0
  83. data/spec/lib/active_data/model/attributes/attribute_spec.rb +144 -0
  84. data/spec/lib/active_data/model/attributes/base_spec.rb +82 -0
  85. data/spec/lib/active_data/model/attributes/collection_spec.rb +73 -0
  86. data/spec/lib/active_data/model/attributes/dictionary_spec.rb +93 -0
  87. data/spec/lib/active_data/model/attributes/localized_spec.rb +88 -33
  88. data/spec/lib/active_data/model/attributes/reflections/attribute_spec.rb +72 -0
  89. data/spec/lib/active_data/model/attributes/reflections/base_spec.rb +56 -0
  90. data/spec/lib/active_data/model/attributes/reflections/collection_spec.rb +37 -0
  91. data/spec/lib/active_data/model/attributes/reflections/dictionary_spec.rb +43 -0
  92. data/spec/lib/active_data/model/attributes/reflections/localized_spec.rb +37 -0
  93. data/spec/lib/active_data/model/attributes/reflections/represents_spec.rb +70 -0
  94. data/spec/lib/active_data/model/attributes/represents_spec.rb +153 -0
  95. data/spec/lib/active_data/model/attributes_spec.rb +243 -0
  96. data/spec/lib/active_data/model/callbacks_spec.rb +338 -0
  97. data/spec/lib/active_data/model/conventions_spec.rb +12 -0
  98. data/spec/lib/active_data/model/dirty_spec.rb +75 -0
  99. data/spec/lib/active_data/model/lifecycle_spec.rb +330 -0
  100. data/spec/lib/active_data/model/nested_attributes.rb +202 -0
  101. data/spec/lib/active_data/model/persistence_spec.rb +47 -0
  102. data/spec/lib/active_data/model/primary_spec.rb +84 -0
  103. data/spec/lib/active_data/model/scopes_spec.rb +88 -0
  104. data/spec/lib/active_data/model/typecasting_spec.rb +192 -0
  105. data/spec/lib/active_data/model/validations/associated_spec.rb +94 -0
  106. data/spec/lib/active_data/model/validations/nested_spec.rb +93 -0
  107. data/spec/lib/active_data/model/validations_spec.rb +31 -0
  108. data/spec/lib/active_data/model_spec.rb +1 -32
  109. data/spec/lib/active_data_spec.rb +12 -0
  110. data/spec/spec_helper.rb +39 -0
  111. data/spec/support/model_helpers.rb +10 -0
  112. metadata +246 -54
  113. data/gemfiles/Gemfile.rails-3 +0 -14
  114. data/lib/active_data/attributes/base.rb +0 -69
  115. data/lib/active_data/attributes/localized.rb +0 -42
  116. data/lib/active_data/model/associations/association.rb +0 -30
  117. data/lib/active_data/model/attributable.rb +0 -122
  118. data/lib/active_data/model/collectionizable.rb +0 -55
  119. data/lib/active_data/model/collectionizable/proxy.rb +0 -42
  120. data/lib/active_data/model/extensions.rb +0 -9
  121. data/lib/active_data/model/extensions/array.rb +0 -24
  122. data/lib/active_data/model/extensions/big_decimal.rb +0 -17
  123. data/lib/active_data/model/extensions/boolean.rb +0 -38
  124. data/lib/active_data/model/extensions/date.rb +0 -17
  125. data/lib/active_data/model/extensions/date_time.rb +0 -17
  126. data/lib/active_data/model/extensions/float.rb +0 -17
  127. data/lib/active_data/model/extensions/hash.rb +0 -22
  128. data/lib/active_data/model/extensions/integer.rb +0 -17
  129. data/lib/active_data/model/extensions/localized.rb +0 -22
  130. data/lib/active_data/model/extensions/object.rb +0 -17
  131. data/lib/active_data/model/extensions/string.rb +0 -17
  132. data/lib/active_data/model/extensions/time.rb +0 -17
  133. data/lib/active_data/model/localizable.rb +0 -31
  134. data/lib/active_data/model/nested_attributes.rb +0 -58
  135. data/lib/active_data/model/parameterizable.rb +0 -29
  136. data/lib/active_data/validations.rb +0 -7
  137. data/lib/active_data/validations/associated.rb +0 -17
  138. data/spec/lib/active_data/model/attributable_spec.rb +0 -191
  139. data/spec/lib/active_data/model/collectionizable_spec.rb +0 -60
  140. data/spec/lib/active_data/model/nested_attributes_spec.rb +0 -67
  141. data/spec/lib/active_data/model/type_cast_spec.rb +0 -116
  142. data/spec/lib/active_data/validations/associated_spec.rb +0 -88
@@ -1,14 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gemspec path: '../'
4
-
5
- gem 'activesupport', '~> 3.0'
6
- gem 'activemodel', '~> 3.0'
7
-
8
- group :test do
9
- gem 'guard'
10
- gem 'guard-rspec'
11
- gem 'rb-inotify', require: false
12
- gem 'rb-fsevent', require: false
13
- gem 'rb-fchange', require: false
14
- end
@@ -1,69 +0,0 @@
1
- module ActiveData
2
- module Attributes
3
- class Base
4
- attr_reader :name, :options
5
-
6
- def initialize name, options = {}, &block
7
- @name = name.to_sym
8
- @options = options
9
- @options[:default] = block if block
10
- end
11
-
12
- def type
13
- @type ||= options[:type] || Object
14
- end
15
-
16
- def values
17
- @values ||= options[:in].dup if options[:in]
18
- end
19
-
20
- def default
21
- @default ||= @options[:default]
22
- end
23
-
24
- def default_blank?
25
- @default_blank ||= !!@options[:default_blank]
26
- end
27
-
28
- def default_value instance
29
- default.respond_to?(:call) ? default.call(instance) : default unless default.nil?
30
- end
31
-
32
- def type_cast value
33
- return value if value.instance_of?(type)
34
- type.active_data_type_cast(value)
35
- end
36
-
37
- def generate_instance_methods context
38
- context.class_eval <<-EOS
39
- def #{name}
40
- read_attribute(:#{name})
41
- end
42
-
43
- def #{name}= value
44
- write_attribute(:#{name}, value)
45
- end
46
-
47
- def #{name}?
48
- read_attribute(:#{name}).present?
49
- end
50
-
51
- def #{name}_before_type_cast
52
- read_attribute_before_type_cast(:#{name})
53
- end
54
- EOS
55
- end
56
-
57
- def generate_class_methods context
58
- if values
59
- context.class_eval <<-EOS
60
- def #{name}_values
61
- _attributes[:#{name}].values
62
- end
63
- EOS
64
- end
65
- end
66
-
67
- end
68
- end
69
- end
@@ -1,42 +0,0 @@
1
- module ActiveData
2
- module Attributes
3
- class Localized < Base
4
-
5
- def default_value *args
6
- {}
7
- end
8
-
9
- def generate_instance_methods context
10
- context.class_eval <<-EOS
11
- def #{name}_translations
12
- read_attribute(:#{name})
13
- end
14
-
15
- def #{name}_translations= value
16
- write_attribute(:#{name}, value)
17
- end
18
-
19
- def #{name}
20
- read_localized_attribute(:#{name})
21
- end
22
-
23
- def #{name}= value
24
- write_localized_attribute(:#{name}, value)
25
- end
26
-
27
- def #{name}?
28
- read_localized_attribute(:#{name}).present?
29
- end
30
-
31
- def #{name}_before_type_cast
32
- read_localized_attribute_before_type_cast(:#{name})
33
- end
34
- EOS
35
- end
36
-
37
- def generate_class_methods context
38
- end
39
-
40
- end
41
- end
42
- end
@@ -1,30 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Associations
4
- class Association
5
- attr_reader :name, :klass, :options
6
-
7
- def initialize name, options = {}
8
- @name, @options = name.to_s, options
9
- @klass ||= options[:class] || (options[:class_name].to_s.presence || name.to_s.classify).safe_constantize
10
- raise "Can not determine class for `#{name}` association" unless @klass
11
- end
12
-
13
- def class_name
14
- klass.to_s
15
- end
16
-
17
- def define_accessor klass
18
- define_reader klass
19
- define_writer klass
20
- end
21
-
22
- def define_reader klass
23
- end
24
-
25
- def define_writer klass
26
- end
27
- end
28
- end
29
- end
30
- end
@@ -1,122 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Attributable
4
- extend ActiveSupport::Concern
5
-
6
- included do
7
- class_attribute :_attributes, :instance_reader => false, :instance_writer => false
8
- self._attributes = {}
9
-
10
- delegate :attribute_default, :to => 'self.class'
11
- end
12
-
13
- module ClassMethods
14
- def attribute name, options = {}, &block
15
- attribute = build_attribute(name, options, &block)
16
- self._attributes = _attributes.merge(attribute.name => attribute)
17
-
18
- attribute.generate_instance_methods generated_instance_attributes_methods
19
- attribute.generate_class_methods generated_class_attributes_methods
20
- attribute
21
- end
22
-
23
- def build_attribute name, options = {}, &block
24
- klass = case options[:type].to_s
25
- when 'Localized'
26
- ActiveData::Attributes::Localized
27
- else
28
- ActiveData::Attributes::Base
29
- end
30
- klass.new name, options, &block
31
- end
32
-
33
- def generated_class_attributes_methods
34
- @generated_class_attributes_methods ||= Module.new.tap { |proxy| extend proxy }
35
- end
36
-
37
- def generated_instance_attributes_methods
38
- @generated_instance_attributes_methods ||= Module.new.tap { |proxy| include proxy }
39
- end
40
-
41
- def initialize_attributes
42
- Hash[_attributes.map { |(name, _)| [name, nil] }]
43
- end
44
- end
45
-
46
- def read_attribute name
47
- name = name.to_sym
48
- if attributes_cache.key? name
49
- attributes_cache[name]
50
- else
51
- attribute = self.class._attributes[name]
52
- value = attribute.type_cast @attributes[name]
53
- use_default = attribute.default_blank? && value.respond_to?(:empty?) ? value.empty? : value.nil?
54
- attributes_cache[name] = use_default ? attribute.default_value(self) : value
55
- end
56
- end
57
- alias_method :[], :read_attribute
58
-
59
- def has_attribute? name
60
- @attributes.key? name.to_sym
61
- end
62
-
63
- def read_attribute_before_type_cast name
64
- @attributes[name.to_sym]
65
- end
66
-
67
- def write_attribute name, value
68
- name = name.to_sym
69
- attributes_cache.delete name
70
- @attributes[name] = value
71
- end
72
- alias_method :[]=, :write_attribute
73
-
74
- def attributes
75
- Hash[attribute_names.map { |name| [name, send(name)] }]
76
- end
77
-
78
- def present_attributes
79
- Hash[attribute_names.map do |name|
80
- value = send(name)
81
- [name, value] unless value.respond_to?(:empty?) ? value.empty? : value.nil?
82
- end.compact]
83
- end
84
-
85
- def attribute_names
86
- @attributes.keys
87
- end
88
-
89
- def attributes= attributes
90
- assign_attributes(attributes)
91
- end
92
- alias_method :update_attributes, :attributes=
93
-
94
- def write_attributes attributes
95
- attributes.each { |(name, value)| send("#{name}=", value) }
96
- end
97
-
98
- def reverse_update_attributes attributes
99
- reverse_assign_attributes(attributes)
100
- end
101
-
102
- private
103
-
104
- def attributes_cache
105
- @attributes_cache ||= {}
106
- end
107
-
108
- def assign_attributes attributes
109
- (attributes.presence || {}).each do |(name, value)|
110
- send("#{name}=", value) if has_attribute?(name) || respond_to?("#{name}=")
111
- end
112
- end
113
-
114
- def reverse_assign_attributes attributes
115
- (attributes.presence || {}).each do |(name, value)|
116
- send("#{name}=", value) if respond_to?("#{name}=") && respond_to?(name) && send(name).blank?
117
- end
118
- end
119
-
120
- end
121
- end
122
- end
@@ -1,55 +0,0 @@
1
- require 'active_data/model/collectionizable/proxy'
2
-
3
- module ActiveData
4
- module Model
5
- module Collectionizable
6
- extend ActiveSupport::Concern
7
-
8
- included do
9
- class_attribute :_collection_superclass
10
- collectionize
11
- end
12
-
13
- module ClassMethods
14
-
15
- def collectionize collection_superclass = Array
16
- self._collection_superclass = collection_superclass
17
- end
18
-
19
- def respond_to_missing? method, include_private
20
- super || collection_class.superclass.method_defined?(method)
21
- end
22
-
23
- def method_missing method, *args, &block
24
- collection_class.superclass.method_defined?(method) ?
25
- current_scope.send(method, *args, &block) :
26
- super
27
- end
28
-
29
- def collection source = nil
30
- collection_class.new source
31
- end
32
-
33
- def collection_class
34
- @collection_class ||= begin
35
- Class.new(_collection_superclass) do
36
- include ActiveData::Model::Collectionizable::Proxy
37
- end.tap { |klass| klass.collectible = self }
38
- end
39
- end
40
-
41
- def current_scope= value
42
- @current_scope = value
43
- end
44
-
45
- def current_scope
46
- @current_scope ||= collection(load)
47
- end
48
- alias :scope :current_scope
49
-
50
- def load; end
51
-
52
- end
53
- end
54
- end
55
- end
@@ -1,42 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Collectionizable
4
- module Proxy
5
- extend ActiveSupport::Concern
6
-
7
- included do
8
- class_attribute :collectible
9
-
10
- def initialize source = nil
11
- source ||= self.class.superclass.new
12
- super source.map { |entity| collectible.instantiate(entity) }
13
- end
14
- end
15
-
16
- def respond_to? method
17
- super || collectible.respond_to?(method)
18
- end
19
-
20
- def method_missing method, *args, &block
21
- result = with_scope { collectible.send(method, *args, &block) }
22
- result = self.class.new result if result.instance_of? self.class.superclass
23
- result
24
- end
25
-
26
- def with_scope
27
- previous_scope = collectible.current_scope
28
- collectible.current_scope = self
29
- result = yield
30
- collectible.current_scope = previous_scope
31
- result
32
- end
33
-
34
- module ClassMethods
35
- def active_data_type_cast value
36
- new value
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,9 +0,0 @@
1
- unless defined?(Boolean)
2
- class Boolean; end
3
- end
4
-
5
- unless defined?(Localized)
6
- class Localized; end
7
- end
8
-
9
- Dir["#{File.dirname(__FILE__)}/extensions/*.rb"].each { |f| require f }
@@ -1,24 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Extensions
4
- module Array
5
- extend ActiveSupport::Concern
6
-
7
- module ClassMethods
8
- def active_data_type_cast value
9
- case value
10
- when ::Array then
11
- value
12
- when ::String then
13
- value.split(',').map(&:strip)
14
- else
15
- nil
16
- end
17
- end
18
- end
19
- end
20
- end
21
- end
22
- end
23
-
24
- Array.send :include, ActiveData::Model::Extensions::Array
@@ -1,17 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Extensions
4
- module BigDecimal
5
- extend ActiveSupport::Concern
6
-
7
- module ClassMethods
8
- def active_data_type_cast value
9
- ::BigDecimal.new Float(value).to_s rescue nil if value
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
16
-
17
- BigDecimal.send :include, ActiveData::Model::Extensions::BigDecimal
@@ -1,38 +0,0 @@
1
- module ActiveData
2
- module Model
3
- module Extensions
4
- module Boolean
5
- extend ActiveSupport::Concern
6
-
7
- MAPPING = {
8
- 1 => true,
9
- 0 => false,
10
- '1' => true,
11
- '0' => false,
12
- 't' => true,
13
- 'f' => false,
14
- 'T' => true,
15
- 'F' => false,
16
- true => true,
17
- false => false,
18
- 'true' => true,
19
- 'false' => false,
20
- 'TRUE' => true,
21
- 'FALSE' => false,
22
- 'y' => true,
23
- 'n' => false,
24
- 'yes' => true,
25
- 'no' => false,
26
- }
27
-
28
- module ClassMethods
29
- def active_data_type_cast value
30
- MAPPING[value]
31
- end
32
- end
33
- end
34
- end
35
- end
36
- end
37
-
38
- Boolean.send :include, ActiveData::Model::Extensions::Boolean