trax_core 0.0.84 → 0.0.85
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +2 -2
- data/lib/trax/core/definitions.rb +4 -4
- data/lib/trax/core/ext/hash.rb +15 -5
- data/lib/trax/core/ext/method.rb +95 -0
- data/lib/trax/core/ext/object.rb +7 -2
- data/lib/trax/core/fields.rb +4 -0
- data/lib/trax/core/has_mixins.rb +5 -1
- data/lib/trax/core/transformer.rb +244 -0
- data/lib/trax/core/types/boolean.rb +1 -0
- data/lib/trax/core/types/enum.rb +7 -8
- data/lib/trax/core/types/enum_value.rb +4 -10
- data/lib/trax/core/types/json.rb +8 -0
- data/lib/trax/core/types/struct.rb +45 -4
- data/lib/trax/core/types/value_object.rb +7 -1
- data/lib/trax/core.rb +13 -0
- data/lib/trax_core/version.rb +1 -1
- data/spec/support/defs.rb +29 -1
- data/spec/support/storefront/product.rb +2 -0
- data/spec/trax/array_spec.rb +2 -6
- data/spec/trax/core/definitions_spec.rb +76 -2
- data/spec/trax/core/eager_autoload_namespace_spec.rb +4 -4
- data/spec/trax/core/errors_spec.rb +10 -15
- data/spec/trax/core/ext/array_spec.rb +2 -2
- data/spec/trax/core/ext/class_spec.rb +3 -3
- data/spec/trax/core/ext/hash_spec.rb +10 -0
- data/spec/trax/core/ext/method_spec.rb +104 -0
- data/spec/trax/core/ext/module_spec.rb +5 -5
- data/spec/trax/core/ext/object_spec.rb +5 -5
- data/spec/trax/core/transformer_spec.rb +170 -0
- data/spec/trax/core/types/array_spec.rb +4 -4
- data/spec/trax/core/types/enum_spec.rb +23 -18
- data/spec/trax/core/types/struct_spec.rb +50 -7
- data/spec/trax/core/types/value_object_spec.rb +6 -0
- data/spec/trax/core_spec.rb +1 -3
- data/spec/trax/hash_spec.rb +13 -15
- data/trax_core.gemspec +7 -6
- metadata +97 -5
- data/spec/trax/core/inheritance_spec.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 607a79a7c4082da1e2a834475a6d4f9cdd0ae5e5
|
4
|
+
data.tar.gz: 77f3a354d9981ac41cdbbc16c5786f9788c62ab7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10c480758ec396d9175a51272457c24fbd8d1da41a354a93bce0163760e60add4d177213d83e8faf780e9f0cc76177912453f7472d424c664a4bde73bde83743
|
7
|
+
data.tar.gz: aa5dadf5ea48099d9b44b7da1f0b54bd2520e2c98b80b3eed7106da6b465f3f3d490dda21bb0c240f2d489459e6645b8421ea562a9f2044a224b3e1475f16a6d
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -6,8 +6,8 @@ module Trax
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def enum(klass_name, **options, &block)
|
9
|
-
attribute_klass = if options.key?(:
|
10
|
-
_klass_prototype = options[:
|
9
|
+
attribute_klass = if options.key?(:extends)
|
10
|
+
_klass_prototype = options[:extends].constantize.clone
|
11
11
|
::Trax::Core::NamedClass.new("#{self.name}::#{klass_name}", _klass_prototype, :parent_definition => self, &block)
|
12
12
|
else
|
13
13
|
::Trax::Core::NamedClass.new("#{self.name}::#{klass_name}", ::Trax::Core::Types::Enum, :parent_definition => self, &block)
|
@@ -17,8 +17,8 @@ module Trax
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def struct(klass_name, **options, &block)
|
20
|
-
attribute_klass = if options.key?(:
|
21
|
-
_klass_prototype = options[:
|
20
|
+
attribute_klass = if options.key?(:extends)
|
21
|
+
_klass_prototype = options[:extends].constantize.clone
|
22
22
|
::Trax::Core::NamedClass.new("#{self.name}::#{klass_name}", _klass_prototype, :parent_definition => self, &block)
|
23
23
|
else
|
24
24
|
::Trax::Core::NamedClass.new("#{self.name}::#{klass_name}", ::Trax::Core::Types::Struct, :parent_definition => self, &block)
|
data/lib/trax/core/ext/hash.rb
CHANGED
@@ -1,21 +1,27 @@
|
|
1
|
-
|
1
|
+
module HashExtensions
|
2
|
+
def assert_required_keys(*args)
|
3
|
+
missing_args = args.reject{|arg| self.key?(arg) }
|
4
|
+
raise ArgumentError.new("Missing keys: #{missing_args.join(', ')}") if missing_args.any?
|
5
|
+
self
|
6
|
+
end
|
7
|
+
|
2
8
|
## Returns selected keys, named or renamed as specified
|
3
9
|
# myproduct = {:name => "something", :price => "20"}
|
4
|
-
# liability = myproduct.tap(&{:cost => :price})
|
10
|
+
# liability = myproduct.tap(&{:cost => :price}.to_transformer)
|
5
11
|
# liability[:cost] == 20
|
6
12
|
## Note: Tap only works where source is a hash object, so use as otherwise
|
7
13
|
# (because tap always returns the object you are tapping)
|
8
14
|
# myproduct = ::OpenStruct.new({:name => "something", :price => "20"})
|
9
|
-
# liability.as!(
|
15
|
+
# liability.as!({:cost => :price})
|
10
16
|
# liability[:cost] == 20
|
11
17
|
#
|
12
18
|
# Transforming values:
|
13
19
|
# Pass a hash as the value with the key being the source key/method
|
14
20
|
# myproduct = ::OpenStruct.new({:name => "something", :price => "20"})
|
15
|
-
# my_sale_product = myproduct.as!(
|
21
|
+
# my_sale_product = myproduct.as!({:sale_price => {:price => ->(val){ val / 2 } } })
|
16
22
|
# my_sale_product[:sale_price] == 10
|
17
23
|
|
18
|
-
def
|
24
|
+
def to_transformer
|
19
25
|
->(hash_or_object) {
|
20
26
|
new_hash = {}
|
21
27
|
|
@@ -48,3 +54,7 @@ class Hash
|
|
48
54
|
}
|
49
55
|
end
|
50
56
|
end
|
57
|
+
|
58
|
+
class Hash
|
59
|
+
include HashExtensions
|
60
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module MethodExtensions
|
2
|
+
# method(method_name).parameters returns an array of the parameters it accepts as well as the signature type
|
3
|
+
# :req = required, ordinal argument, i.e. def foo(one)
|
4
|
+
# :opt = optional ordinal argument, i.e. def foo(one=nil)
|
5
|
+
# :keyreq = required keyword argument i.e. def foo(req:)
|
6
|
+
# :key = optional keyword argument, i.e. def foo(one:nil)
|
7
|
+
# :rest = optional arguments splat, i.e. def foo(*args)
|
8
|
+
# :keyrest = optional keyword arguments splat, i.e. def foo(**args)
|
9
|
+
|
10
|
+
STRATEGIES_FOR_SEND_WHEN_METHOD = {
|
11
|
+
:accepts_nothing? => :strategy_for_method_without_arguments,
|
12
|
+
:accepts_arguments_and_keywords? => :strategy_for_method_with_arguments_and_keywords,
|
13
|
+
:accepts_arguments? => :strategy_for_method_with_arguments,
|
14
|
+
:accepts_keywords? => :strategy_for_method_with_keywords
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
def accepted_argument_signatures
|
18
|
+
@accepted_argument_signatures ||= self.parameters.any? ? self.parameters.map(&:first).uniq : []
|
19
|
+
end
|
20
|
+
|
21
|
+
def accepts_something?
|
22
|
+
@accepts_something ||= arity != 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def accepts_nothing?
|
26
|
+
!accepts_something?
|
27
|
+
end
|
28
|
+
|
29
|
+
def accepts_arguments?
|
30
|
+
@accepts_arguments ||= requires_arguments? || accepts_optional_arguments? || accepts_arguments_splat?
|
31
|
+
end
|
32
|
+
|
33
|
+
def accepts_keywords?
|
34
|
+
@accepts_keywords ||= requires_keywords? || accepts_optional_keywords? || accepts_keywords_splat?
|
35
|
+
end
|
36
|
+
|
37
|
+
def accepts_arguments_and_keywords?
|
38
|
+
@accepts_arguments_and_keywords ||= accepts_arguments? && accepts_keywords?
|
39
|
+
end
|
40
|
+
|
41
|
+
def accepts_arguments_splat?
|
42
|
+
@accepts_arguments_splat ||= accepted_argument_signatures.include?(:rest)
|
43
|
+
end
|
44
|
+
|
45
|
+
def accepts_keywords_splat?
|
46
|
+
@accepts_keywords_splat ||= accepted_argument_signatures.include?(:keyrest)
|
47
|
+
end
|
48
|
+
|
49
|
+
def accepts_optional_arguments?
|
50
|
+
@accepts_optional_arguments ||= accepted_argument_signatures.include?(:opt)
|
51
|
+
end
|
52
|
+
|
53
|
+
def accepts_optional_keywords?
|
54
|
+
@accepts_optional_keywords ||= accepted_argument_signatures.include?(:key)
|
55
|
+
end
|
56
|
+
|
57
|
+
def execute_call_strategy(*args, **options)
|
58
|
+
__send__(strategy_for_call)
|
59
|
+
end
|
60
|
+
|
61
|
+
def requires_arguments?
|
62
|
+
@requires_arguments ||= accepted_argument_signatures.include?(:req)
|
63
|
+
end
|
64
|
+
|
65
|
+
def requires_keywords?
|
66
|
+
@requires_keywords ||= accepted_argument_signatures.include?(:keyreq)
|
67
|
+
end
|
68
|
+
|
69
|
+
def strategy_for_method_without_arguments(*args, **options)
|
70
|
+
call()
|
71
|
+
end
|
72
|
+
|
73
|
+
def strategy_for_method_with_keywords(*args, **options)
|
74
|
+
call(**options)
|
75
|
+
end
|
76
|
+
|
77
|
+
def strategy_for_method_with_arguments(*args, **options)
|
78
|
+
call(*args)
|
79
|
+
end
|
80
|
+
|
81
|
+
def strategy_for_method_with_arguments_and_keywords(*args, **options)
|
82
|
+
call(*args, **options)
|
83
|
+
end
|
84
|
+
|
85
|
+
def strategy_for_call
|
86
|
+
@strategy_for_call ||= begin
|
87
|
+
first_matching_question = STRATEGIES_FOR_SEND_WHEN_METHOD.keys.detect{ |k| send(k) }
|
88
|
+
STRATEGIES_FOR_SEND_WHEN_METHOD[first_matching_question]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class Method
|
94
|
+
include MethodExtensions
|
95
|
+
end
|
data/lib/trax/core/ext/object.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
require "active_support/core_ext/object/try"
|
2
2
|
class Object
|
3
|
-
def
|
4
|
-
|
3
|
+
def __smartsend__(method_name, *args, **options)
|
4
|
+
target = method(method_name)
|
5
|
+
target.execute_call_strategy(*args, **options)
|
6
|
+
end
|
7
|
+
|
8
|
+
def as!(h)
|
9
|
+
h.to_transformer.call(self)
|
5
10
|
end
|
6
11
|
|
7
12
|
# Defines a Configuration Class within a target module namespace, or nested class
|
data/lib/trax/core/fields.rb
CHANGED
data/lib/trax/core/has_mixins.rb
CHANGED
@@ -21,7 +21,11 @@ module Trax
|
|
21
21
|
|
22
22
|
mixin_module = base.const_set("Mixin", ::Module.new)
|
23
23
|
mixin_module.module_attribute(:mixin_namespace) { base }
|
24
|
-
|
24
|
+
|
25
|
+
# NOTE: This line causes specs to fail, because it loads before
|
26
|
+
# ::Trax::Core::Definitions. It's currently not being used by any other
|
27
|
+
# Trax gems, so we'll have to revisit this whenever they start using it
|
28
|
+
#mixin_module.extend(::Trax::Core::Mixin)
|
25
29
|
|
26
30
|
mixin_module.module_eval do
|
27
31
|
def self.extended(base)
|
@@ -0,0 +1,244 @@
|
|
1
|
+
module Trax
|
2
|
+
module Core
|
3
|
+
class Transformer < SimpleDelegator
|
4
|
+
attr_reader :input, :parent, :output
|
5
|
+
|
6
|
+
def self.inherited(subklass)
|
7
|
+
subklass.class_attribute :properties
|
8
|
+
subklass.properties = {}.with_indifferent_access
|
9
|
+
subklass.class_attribute :after_initialize_callbacks
|
10
|
+
subklass.after_initialize_callbacks = ::Set.new
|
11
|
+
subklass.class_attribute :after_transform_callbacks
|
12
|
+
subklass.after_transform_callbacks = ::Set.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.after_initialize(&block)
|
16
|
+
after_initialize_callbacks << block
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.after_transform(&block)
|
20
|
+
after_transform_callbacks << block
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.properties_with_default_values
|
24
|
+
@properties_with_default_values ||= properties.values.select{ |prop| prop.try(:default) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.nested_properties
|
28
|
+
@nested_properties ||= properties.values.select{|prop| prop.is_nested? }
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.transformer_properties
|
32
|
+
@transformer_properties ||= properties.values.select{|prop| prop.ancestors.include?(::Trax::Core::Transformer) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.transformer_properties_with_after_transform_callbacks
|
36
|
+
@transformer_properties_with_after_transform_callbacks ||= transformer_properties.select{|prop| prop.after_transform_callbacks.any? }
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.is_nested?
|
40
|
+
!!self.try(:parent_definition)
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.from_parent?
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.property(_property_name, **options, &block)
|
48
|
+
options[:parent_definition] = self
|
49
|
+
options[:property_name] = _property_name
|
50
|
+
options[:with] = block if block_given?
|
51
|
+
transformer_klass_name = "#{name}::#{_property_name.camelize}"
|
52
|
+
transformer_klass = ::Trax::Core::NamedClass.new(transformer_klass_name, Property, **options)
|
53
|
+
self.properties[_property_name] = transformer_klass
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.transformer(_property_name, **options, &block)
|
57
|
+
options[:parent_definition] = self
|
58
|
+
options[:property_name] = _property_name
|
59
|
+
options[:default] = ->(){ {}.with_indifferent_access } unless options.key?(:default)
|
60
|
+
options[:with] = block if block_given?
|
61
|
+
transformer_klass_name = "#{name}::#{_property_name.camelize}"
|
62
|
+
transformer_klass = ::Trax::Core::NamedClass.new(transformer_klass_name, Transformer, **options, &block)
|
63
|
+
self.properties[_property_name] = transformer_klass
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.nested(*args, **options, &block)
|
67
|
+
transformer(*args, **options, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.fetch_property_from_object(_property, obj)
|
71
|
+
if _property.include?('/')
|
72
|
+
property_chain = _property.split('/')
|
73
|
+
obj.dig(*property_chain)
|
74
|
+
else
|
75
|
+
obj[_property]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def initialize(obj={}, parent=nil)
|
80
|
+
@input = obj.dup
|
81
|
+
@output = {}.with_indifferent_access
|
82
|
+
@parent = parent if parent
|
83
|
+
|
84
|
+
initialize_output_properties
|
85
|
+
initialize_default_values
|
86
|
+
run_after_initialize_callbacks if run_after_initialize_callbacks?
|
87
|
+
run_after_transform_callbacks if run_after_transform_callbacks?
|
88
|
+
end
|
89
|
+
|
90
|
+
def [](_property)
|
91
|
+
if _property.include?('/')
|
92
|
+
property_chain = _property.split('/')
|
93
|
+
self.dig(*property_chain)
|
94
|
+
else
|
95
|
+
super(_property)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def key?(_property)
|
100
|
+
if _property.include?('/')
|
101
|
+
property_chain = _property.split('/')
|
102
|
+
!!self.dig(*property_chain)
|
103
|
+
else
|
104
|
+
super(_property)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def has_parent?
|
109
|
+
!!parent
|
110
|
+
end
|
111
|
+
|
112
|
+
def parent_key?(k)
|
113
|
+
return false unless has_parent?
|
114
|
+
|
115
|
+
parent.key?(k)
|
116
|
+
end
|
117
|
+
|
118
|
+
def __getobj__
|
119
|
+
@output
|
120
|
+
end
|
121
|
+
|
122
|
+
def to_hash
|
123
|
+
@to_hash ||= begin
|
124
|
+
duplicate_hash = self.__getobj__.dup
|
125
|
+
|
126
|
+
duplicate_hash.each_pair do |k, v|
|
127
|
+
if v.is_a?(::Trax::Core::Transformer)
|
128
|
+
duplicate_hash[k] = v.__getobj__
|
129
|
+
elsif v.is_a?(Property)
|
130
|
+
duplicate_hash[k] = v.__getobj__
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
duplicate_hash
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def to_recursive_hash
|
139
|
+
@to_recursive_hash ||= begin
|
140
|
+
duplicate_hash = self.__getobj__.dup
|
141
|
+
|
142
|
+
self.each_pair do |k, v|
|
143
|
+
if v.is_a?(::Trax::Core::Transformer)
|
144
|
+
duplicate_hash[k] = v.to_hash
|
145
|
+
elsif v.is_a?(Property)
|
146
|
+
duplicate_hash[k] = v.__getobj__
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
duplicate_hash
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
def initialize_default_values
|
157
|
+
self.class.properties_with_default_values.each do |prop|
|
158
|
+
unless @output.key?(prop.property_name)
|
159
|
+
if prop.default.is_a?(Proc)
|
160
|
+
@output[prop.property_name] = prop.default.arity > 0 ? prop.default.call(@output) : prop.default.call
|
161
|
+
else
|
162
|
+
@output[prop.property_name] = prop.default
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def initialize_output_properties
|
169
|
+
self.class.properties.each_pair do |k,property_klass|
|
170
|
+
if @input.key?(property_klass.property_name)
|
171
|
+
value = @input[property_klass.property_name]
|
172
|
+
@output[property_klass.property_name] = property_klass.new(value, self)
|
173
|
+
elsif @input.key?(property_klass.try(:from))
|
174
|
+
value = @input[property_klass.from]
|
175
|
+
@output[property_klass.property_name] = property_klass.new(value, self)
|
176
|
+
elsif property_klass.from_parent?
|
177
|
+
value = self.class.fetch_property_from_object(property_klass.from_parent, self.parent.input)
|
178
|
+
@output[property_klass.property_name] = property_klass.new(value, self)
|
179
|
+
elsif property_klass.ancestors.include?(::Trax::Core::Transformer)
|
180
|
+
value = if property_klass.default.is_a?(Proc)
|
181
|
+
property_klass.default.arity > 0 ? property_klass.default.call(self) : property_klass.default.call
|
182
|
+
else
|
183
|
+
property_klass.default
|
184
|
+
end
|
185
|
+
|
186
|
+
@output[property_klass.property_name] = property_klass.new(value, self)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
#will not transform output based on callback result
|
192
|
+
def run_after_initialize_callbacks
|
193
|
+
self.class.after_initialize_callbacks.each do |callback|
|
194
|
+
@output.instance_eval(&callback)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def run_after_initialize_callbacks?
|
199
|
+
self.class.after_initialize_callbacks.any?
|
200
|
+
end
|
201
|
+
|
202
|
+
#will transform output with return of each callback
|
203
|
+
def run_after_transform_callbacks
|
204
|
+
self.class.after_transform_callbacks.each do |callback|
|
205
|
+
@output = self.instance_exec(@output, &callback)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def run_after_transform_callbacks?
|
210
|
+
self.class.after_transform_callbacks.any?
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
class Property < SimpleDelegator
|
215
|
+
def self.is_nested?
|
216
|
+
@is_nested ||= !!self.try(:parent_definition)
|
217
|
+
end
|
218
|
+
|
219
|
+
def self.is_translated?
|
220
|
+
@is_translated ||= !!self.try(:from)
|
221
|
+
end
|
222
|
+
|
223
|
+
def self.from_parent?
|
224
|
+
@from_parent ||= !!try(:from_parent)
|
225
|
+
end
|
226
|
+
|
227
|
+
def initialize(value, transformer)
|
228
|
+
@value = value
|
229
|
+
|
230
|
+
if self.class.try(:with)
|
231
|
+
@value = self.class.with.arity > 1 ? self.class.with.call(@value, transformer) : self.class.with.call(@value)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def nil?
|
236
|
+
__getobj__.nil?
|
237
|
+
end
|
238
|
+
|
239
|
+
def __getobj__
|
240
|
+
@value
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
data/lib/trax/core/types/enum.rb
CHANGED
@@ -15,7 +15,7 @@ module Trax
|
|
15
15
|
class_attribute :allow_nil, :raise_on_invalid
|
16
16
|
|
17
17
|
### Class Methods ###
|
18
|
-
def self.define_enum_value(const_name, val=nil, **attributes)
|
18
|
+
def self.define_enum_value(const_name, val=nil, **attributes, &block)
|
19
19
|
name = "#{const_name}".underscore.to_sym
|
20
20
|
const_name = name.to_s.camelize
|
21
21
|
val = (self._values_hash.length + 1) if val.nil?
|
@@ -23,11 +23,8 @@ module Trax
|
|
23
23
|
raise ::Trax::Core::Errors::DuplicateEnumValue.new(:klass => self.class.name, :value => const_name) if self === name
|
24
24
|
raise ::Trax::Core::Errors::DuplicateEnumValue.new(:klass => self.class.name, :value => val) if self === val
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
self.value = val
|
29
|
-
self.attributes = attributes
|
30
|
-
}
|
26
|
+
value_klass_class_attributes = {:tag => name, :value => val, :attributes => attributes}
|
27
|
+
value_klass = ::Trax::Core::NamedClass.new("#{self.name}::#{const_name}", ::Trax::Core::Types::EnumValue, **value_klass_class_attributes, &block)
|
31
28
|
|
32
29
|
self._values_hash[val] = value_klass
|
33
30
|
self._names_hash[name] = value_klass
|
@@ -134,13 +131,15 @@ module Trax
|
|
134
131
|
end
|
135
132
|
|
136
133
|
def self.to_schema
|
137
|
-
::Trax::Core::Definition.new(
|
134
|
+
result = ::Trax::Core::Definition.new(
|
138
135
|
:name => self.name.demodulize.underscore,
|
139
136
|
:source => self.name,
|
140
|
-
:type =>
|
137
|
+
:type => self.type,
|
141
138
|
:choices => choices.map(&:to_schema),
|
142
139
|
:values => keys
|
143
140
|
)
|
141
|
+
result[:default] = self.default if self.respond_to?(:default)
|
142
|
+
result
|
144
143
|
end
|
145
144
|
|
146
145
|
class << self
|
@@ -2,13 +2,6 @@ module Trax
|
|
2
2
|
module Core
|
3
3
|
module Types
|
4
4
|
class EnumValue
|
5
|
-
def self.inherited(subclass)
|
6
|
-
super(subclass)
|
7
|
-
self.class_attribute(:tag)
|
8
|
-
self.class_attribute(:value)
|
9
|
-
self.class_attribute(:attributes)
|
10
|
-
end
|
11
|
-
|
12
5
|
def self.as_json(options={})
|
13
6
|
tag.to_s
|
14
7
|
end
|
@@ -42,12 +35,13 @@ module Trax
|
|
42
35
|
:source => self.name,
|
43
36
|
:name => to_s,
|
44
37
|
:type => :enum_value,
|
45
|
-
:integer_value => to_i
|
38
|
+
:integer_value => to_i,
|
39
|
+
:attributes => attributes
|
46
40
|
)
|
47
41
|
end
|
48
42
|
|
49
43
|
def self.inspect
|
50
|
-
":#{tag}"
|
44
|
+
tag ? ":#{tag}" : super
|
51
45
|
end
|
52
46
|
|
53
47
|
def self.include?(val)
|
@@ -60,7 +54,7 @@ module Trax
|
|
60
54
|
end
|
61
55
|
|
62
56
|
def self.===(val)
|
63
|
-
[tag, to_s, to_i].include?(val)
|
57
|
+
[::Trax::Core::Types::Enum, tag, to_s, to_i].include?(val)
|
64
58
|
end
|
65
59
|
end
|
66
60
|
end
|
data/lib/trax/core/types/json.rb
CHANGED
@@ -19,11 +19,11 @@ module Trax
|
|
19
19
|
:array_of => [],
|
20
20
|
:boolean => nil,
|
21
21
|
:enum => nil,
|
22
|
-
:float =>
|
22
|
+
:float => nil,
|
23
23
|
:integer => nil,
|
24
24
|
:json => {},
|
25
25
|
:set => [],
|
26
|
-
:string =>
|
26
|
+
:string => nil,
|
27
27
|
:struct => {},
|
28
28
|
:time => nil
|
29
29
|
}.with_indifferent_access.freeze
|
@@ -134,10 +134,51 @@ module Trax
|
|
134
134
|
alias :time :time_property
|
135
135
|
end
|
136
136
|
|
137
|
+
def reverse_merge(other_hash)
|
138
|
+
self.class.new(other_hash).merge(self)
|
139
|
+
end
|
140
|
+
|
141
|
+
def reverse_merge!(other_hash)
|
142
|
+
self.class.new(other_hash).merge!(self)
|
143
|
+
end
|
144
|
+
|
145
|
+
def reverse_merge_present_values_only
|
146
|
+
other = other_hash.delete_if{|k,v| v.nil? || self.value_present_for_key?(k) }
|
147
|
+
other.keys.each_with_object(self) do |k, result|
|
148
|
+
self.delete(k) if !self.value_present_for_key?(k)
|
149
|
+
end
|
150
|
+
|
151
|
+
self.merge(other)
|
152
|
+
end
|
153
|
+
|
154
|
+
def reverse_merge_present_values_only!(other_hash)
|
155
|
+
other = other_hash.delete_if{|k,v| v.nil? || self.value_present_for_key?(k) }
|
156
|
+
other.keys.each_with_object(self) do |k, result|
|
157
|
+
self.delete(k) if !self.value_present_for_key?(k)
|
158
|
+
end
|
159
|
+
|
160
|
+
self.merge!(other)
|
161
|
+
end
|
162
|
+
|
137
163
|
def value
|
138
164
|
self
|
139
165
|
end
|
140
166
|
|
167
|
+
def value_present_for_key?(k)
|
168
|
+
case self.class.fields_module.all[k].type
|
169
|
+
when :struct
|
170
|
+
!self.__send__(k).empty?
|
171
|
+
when :boolean
|
172
|
+
!self.__send__(k).nil?
|
173
|
+
when :array, :set
|
174
|
+
self.__send__(k) && self.__send__(k).length > 0
|
175
|
+
when :string
|
176
|
+
self.__send__(k).present?
|
177
|
+
else
|
178
|
+
!self.__send__(k).nil?
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
141
182
|
private
|
142
183
|
|
143
184
|
#By default, strings/int/bool wont get cast to value objects
|
@@ -146,8 +187,8 @@ module Trax
|
|
146
187
|
name = name.is_a?(::Symbol) ? name.to_s : name
|
147
188
|
klass_name = "#{fields_module.name.underscore}/#{property_name}".camelize
|
148
189
|
|
149
|
-
attribute_klass = if options.key?(:
|
150
|
-
_klass_prototype = options[:
|
190
|
+
attribute_klass = if options.key?(:extends)
|
191
|
+
_klass_prototype = options[:extends].is_a?(::String) ? options[:extends].safe_constantize : options[:extends]
|
151
192
|
_klass = ::Trax::Core::NamedClass.new(klass_name, _klass_prototype, :parent_definition => self, **options, &block)
|
152
193
|
_klass
|
153
194
|
else
|
@@ -10,6 +10,10 @@ module Trax
|
|
10
10
|
@value
|
11
11
|
end
|
12
12
|
|
13
|
+
def nil?
|
14
|
+
@value.nil?
|
15
|
+
end
|
16
|
+
|
13
17
|
def self.symbolic_name
|
14
18
|
name.demodulize.underscore.to_sym
|
15
19
|
end
|
@@ -19,11 +23,13 @@ module Trax
|
|
19
23
|
end
|
20
24
|
|
21
25
|
def self.to_schema
|
22
|
-
::Trax::Core::Definition.new(
|
26
|
+
result = ::Trax::Core::Definition.new(
|
23
27
|
:name => self.name.demodulize.underscore,
|
24
28
|
:source => self.name,
|
25
29
|
:type => self.type
|
26
30
|
)
|
31
|
+
result[:default] = self.default if self.respond_to?(:default)
|
32
|
+
result
|
27
33
|
end
|
28
34
|
end
|
29
35
|
end
|