trax_model 0.0.91 → 0.0.92

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/lib/trax/model.rb +71 -12
  4. data/lib/trax/model/attributes.rb +40 -0
  5. data/lib/trax/model/attributes/definitions.rb +19 -0
  6. data/lib/trax/model/attributes/errors.rb +15 -0
  7. data/lib/trax/model/attributes/mixin.rb +43 -0
  8. data/lib/trax/model/attributes/type.rb +11 -0
  9. data/lib/trax/model/attributes/types.rb +11 -0
  10. data/lib/trax/model/attributes/types/array.rb +92 -0
  11. data/lib/trax/model/attributes/types/enum.rb +32 -0
  12. data/lib/trax/model/attributes/types/json.rb +76 -0
  13. data/lib/trax/model/attributes/types/uuid_array.rb +83 -0
  14. data/lib/trax/model/attributes/value.rb +9 -0
  15. data/lib/trax/model/config.rb +1 -9
  16. data/lib/trax/model/enum.rb +3 -3
  17. data/lib/trax/model/errors.rb +30 -19
  18. data/lib/trax/model/freezable.rb +1 -1
  19. data/lib/trax/model/mixin.rb +16 -4
  20. data/lib/trax/model/railtie.rb +17 -0
  21. data/lib/trax/model/registry.rb +3 -3
  22. data/lib/trax/model/restorable.rb +26 -17
  23. data/lib/trax/model/struct.rb +31 -0
  24. data/lib/trax/model/unique_id.rb +56 -14
  25. data/lib/trax/model/uuid_array.rb +59 -0
  26. data/lib/trax/model/validators.rb +2 -0
  27. data/lib/trax/validators/boolean_validator.rb +14 -0
  28. data/lib/trax/validators/email_validator.rb +6 -2
  29. data/lib/trax/validators/enum_validator.rb +16 -0
  30. data/lib/trax/validators/json_attribute_validator.rb +19 -0
  31. data/lib/trax_model/version.rb +1 -1
  32. data/spec/support/schema.rb +26 -10
  33. data/spec/trax/model/struct_spec.rb +16 -0
  34. data/spec/trax/model_spec.rb +2 -4
  35. data/trax_model.gemspec +1 -0
  36. metadata +35 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 809159b1a30e397711f6f8dc007fd412b8e689ca
4
- data.tar.gz: b9be65956b716ee4a8750a9edb7f2812d18fdb38
3
+ metadata.gz: d24f88faa95bde183c2a7046d8c1d86b604987bd
4
+ data.tar.gz: 4c124fcd2c0f21166cfc7012b75979af8551d4b7
5
5
  SHA512:
6
- metadata.gz: 71c0453bed5cb715577fed35c59aad6c9a910cb7fc2435a0b423304a5e4af9d00bce47707dfac47165923567030a5b6338c9cc9dc372937d798b366f96b71a0e
7
- data.tar.gz: 562cab67f023f85a5a84b26e76ab3f9dc9d30480c728b0a87534723d25e21d7bb7557134c8ff97fdfee61d61453540ff9a0c3fb73f3d970044f05da84fa55036
6
+ metadata.gz: 5cac8b9cf60e27ab5c532ba6dc7a778319440392240cb38083676cdcaa10466446e8981fac14bca8397132ecc88f006fd551da8e040116a653e5897049cf23c2
7
+ data.tar.gz: 89309b58c39783f84f322664750a05214b9522a7d7be892bcc0a00b269077563404c4622a5c549e57d4fdedd64fe5e7be949266e774279676118b234db2085d2
data/Gemfile CHANGED
@@ -1,3 +1,3 @@
1
1
  source 'https://rubygems.org'
2
-
2
+ gem 'trax_core', :path => "~/gems/trax_core"
3
3
  gemspec
@@ -4,10 +4,12 @@ require 'hashie/dash'
4
4
  require 'hashie/mash'
5
5
  require 'simple_enum'
6
6
  require_relative './string'
7
- # require_relative './enum'
7
+ require_relative './validators/boolean_validator'
8
8
  require_relative './validators/email_validator'
9
+ require_relative './validators/enum_validator'
9
10
  require_relative './validators/frozen_validator'
10
11
  require_relative './validators/future_validator'
12
+ require_relative './validators/json_attribute_validator'
11
13
  require_relative './validators/subdomain_validator'
12
14
  require_relative './validators/url_validator'
13
15
 
@@ -16,6 +18,7 @@ module Trax
16
18
  extend ::ActiveSupport::Concern
17
19
  extend ::ActiveSupport::Autoload
18
20
 
21
+ autoload :Attributes
19
22
  autoload :Config
20
23
  autoload :Enum
21
24
  autoload :Errors
@@ -28,24 +31,38 @@ module Trax
28
31
  autoload :Mixin
29
32
  autoload :MTI
30
33
  autoload :Restorable
34
+ autoload :Railtie
31
35
  autoload :STI
36
+ autoload :Struct
32
37
  autoload :Validators
33
38
 
34
39
  include ::Trax::Model::Matchable
35
40
  include ::ActiveModel::Dirty
36
41
 
42
+ define_configuration_options! do
43
+ option :auto_include, :default => false
44
+ option :auto_include_mixins, :default => []
45
+ end
46
+
37
47
  class << self
38
48
  attr_accessor :mixin_registry
39
49
  end
40
50
 
41
51
  @mixin_registry = {}
42
52
 
43
- def self.register_mixin(mixin_klass)
44
- mixin_key = mixin_klass.name.demodulize.underscore.to_sym
53
+ def self.register_mixin(mixin_klass, key = nil)
54
+ mixin_key = mixin_klass.respond_to?(:mixin_registry_key) ? mixin_klass.mixin_registry_key : (key || mixin_klass.name.demodulize.underscore.to_sym)
55
+
56
+ return if mixin_registry.key?(mixin_key)
45
57
  mixin_registry[mixin_key] = mixin_klass
46
58
  end
47
59
 
60
+ def self.root
61
+ ::Pathname.new(::File.path(__FILE__))
62
+ end
63
+
48
64
  def self.eager_autoload_mixins!
65
+ ::Trax::Model::Attributes::Mixin
49
66
  ::Trax::Model::Enum
50
67
  ::Trax::Model::Freezable
51
68
  ::Trax::Model::Restorable
@@ -55,9 +72,9 @@ module Trax
55
72
  eager_autoload_mixins!
56
73
 
57
74
  included do
58
- class_attribute :trax_defaults
75
+ class_attribute :registered_mixins
59
76
 
60
- self.trax_defaults = ::Trax::Model::Config.new
77
+ self.registered_mixins = {}
61
78
 
62
79
  register_trax_models(self)
63
80
  end
@@ -66,19 +83,57 @@ module Trax
66
83
  delegate :register_trax_model, :to => "::Trax::Model::Registry"
67
84
  delegate :[], :to => :find
68
85
 
69
- def defaults(options = {})
70
- options.each_pair do |key, val|
71
- self.trax_defaults.__send__("#{key}=", val)
86
+ def after_inherited(&block)
87
+ instance_variable_set(:@_after_inherited_block, block)
88
+ end
89
+
90
+ #the tracepoint stuff is to ensure that we call the after_inherited block not
91
+ #right after the class is defined, but rather, after the class is defined and
92
+ #evaluated. i.e. this allows us to do stuff like set class attributes
93
+ # class_attribute :messages_class
94
+ #
95
+ # after_inherited do
96
+ # has_many :computed_subtype_messages, :class_name => message_class
97
+ # end
98
+ # - Then in subklass
99
+ # self.messages_class = "MySubtypeSpecifcModel"
100
+
101
+ def inherited(subklass)
102
+ super(subklass)
103
+
104
+ if self.instance_variable_defined?(:@_after_inherited_block)
105
+ trace = ::TracePoint.new(:end) do |tracepoint|
106
+ if tracepoint.self == subklass
107
+ trace.disable
108
+
109
+ subklass.instance_eval(&self.instance_variable_get(:@_after_inherited_block))
110
+ end
111
+ end
112
+
113
+ trace.enable
72
114
  end
73
115
  end
74
116
 
75
117
  def mixin(key, options = {})
76
- mixin_klass = ::Trax::Model.mixin_registry[key]
118
+ raise ::Trax::Model::Errors::MixinNotRegistered.new(
119
+ model: self.name,
120
+ mixin: key
121
+ ) unless ::Trax::Model.mixin_registry.key?(key)
122
+
123
+ mixin_module = ::Trax::Model.mixin_registry[key]
124
+ self.registered_mixins[key] = mixin_module
77
125
 
78
126
  self.class_eval do
79
- unless self.ancestors.include?(mixin_klass)
80
- include(mixin_klass)
81
- mixin_klass.apply_mixin(self, options) if mixin_klass.respond_to?(:apply_mixin)
127
+ include(mixin_module) unless self.ancestors.include?(mixin_module)
128
+
129
+ options = {} if options.is_a?(TrueClass)
130
+ options = { options => true } if options.is_a?(Symbol)
131
+ mixin_module.apply_mixin(self, options) if mixin_module.respond_to?(:apply_mixin)
132
+
133
+ if mixin_module.instance_variable_defined?(:@_after_included_block)
134
+ block = mixin_module.instance_variable_get(:@_after_included_block)
135
+
136
+ instance_exec(options, &block)
82
137
  end
83
138
  end
84
139
  end
@@ -105,5 +160,9 @@ module Trax
105
160
  name.underscore
106
161
  end
107
162
  end
163
+
164
+ ::ActiveSupport.run_load_hooks(:trax_model, self)
108
165
  end
109
166
  end
167
+
168
+ ::Trax::Model::Railtie if defined?(Rails)
@@ -0,0 +1,40 @@
1
+ require 'hashie/extensions/ignore_undeclared'
2
+
3
+ module Trax
4
+ module Model
5
+ module Attributes
6
+ extend ::ActiveSupport::Autoload
7
+
8
+ autoload :Mixin
9
+ autoload :Definitions
10
+ autoload :Errors
11
+ autoload :Types
12
+ autoload :Type
13
+ autoload :Value
14
+
15
+ define_configuration_options! do
16
+ option :attribute_types, :default => {}
17
+ end
18
+
19
+ def self.register_attribute_type(mod)
20
+ key = mod.name.demodulize.underscore.split('_')[0].to_sym
21
+
22
+ config.attribute_types[key] = mod
23
+ end
24
+
25
+ def self.[](key)
26
+ config.attribute_types[key]
27
+ end
28
+
29
+ def self.key?(type)
30
+ config.attribute_types.has_key?(type)
31
+ end
32
+
33
+ def self.eager_autoload_types!
34
+ ::Trax::Model::Attributes::Types
35
+ end
36
+
37
+ eager_autoload_types!
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,19 @@
1
+ module Trax
2
+ module Model
3
+ module Attributes
4
+ class Definitions < ::SimpleDelegator
5
+ def initialize(model)
6
+ @model = model
7
+ end
8
+
9
+ def __getobj__
10
+ @model
11
+ end
12
+
13
+ def attribute(*args, type:, **options, &block)
14
+ @model.trax_attribute(*args, type: type, **options, &block)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ module Trax
2
+ module Model
3
+ module Attributes
4
+ module Errors
5
+ class UnknownAttributeType < ::Trax::Core::Errors::Base
6
+ argument :type, :required => true
7
+
8
+ message {
9
+ "#{type} is an unknown trax model attribute type"
10
+ }
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,43 @@
1
+ module Trax
2
+ module Model
3
+ module Attributes
4
+ module Mixin
5
+ def self.mixin_registry_key; :attributes end;
6
+
7
+ extend ::Trax::Model::Mixin
8
+
9
+ included do
10
+ class_attribute :trax_attribute_fields
11
+
12
+ self.trax_attribute_fields = ::ActiveSupport::HashWithIndifferentAccess.new
13
+
14
+ ::Trax::Model::Attributes.config.attribute_types.each_pair do |key, mod|
15
+ include mod::Mixin
16
+ end
17
+ end
18
+
19
+ module ClassMethods
20
+ # so we can keep all our definitions in same place, and largely so we
21
+ # can use attribute method to define methods
22
+ #probably overkill but..
23
+ def define_attributes(&block)
24
+ model_klass_proxy = ::Trax::Model::Attributes::Definitions.new(self)
25
+ model_klass_proxy.instance_eval(&block)
26
+ end
27
+
28
+ def trax_attribute(name, type:, **options, &block)
29
+ trax_attribute_fields[type] ||= {}
30
+
31
+ raise ::Trax::Model::Attributes::Errors::UnknownAttributeType.new(type: type) unless ::Trax::Model::Attributes.key?(type)
32
+ attribute_type_definition_method = ::Trax::Model::Attributes[type]::Mixin::ClassMethods.instance_methods.first
33
+
34
+ self.send(attribute_type_definition_method, name, **options, &block)
35
+
36
+ self.validates(name, options[:validates]) if options.key?(:validates)
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,11 @@
1
+ module Trax
2
+ module Model
3
+ module Attributes
4
+ class Type
5
+ def self.inherited(subklass)
6
+ ::Trax::Model::Attributes.register_attribute_type(subklass)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Trax
2
+ module Model
3
+ module Attributes
4
+ module Types
5
+ ::Trax::Core::FS::CurrentDirectory.new['types'].recursive_files.each do |file|
6
+ load file
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,92 @@
1
+ require 'hashie/extensions/ignore_undeclared'
2
+ #totally not working atm :), dont use me!
3
+ module Trax
4
+ module Model
5
+ module Attributes
6
+ module Types
7
+ class Array < ::Trax::Model::Attributes::Type
8
+ class Value < ::Trax::Model::Attributes::Value
9
+ class_attribute :element_class
10
+ include ::Enumerable
11
+
12
+ def initialize(*args)
13
+ @array = super(*args)
14
+ @array.map!{ |ele| self.class.element_class.new(ele) } if self.class.element_class && @array.any?
15
+ end
16
+
17
+ def __getobj__
18
+ @array
19
+ end
20
+
21
+ def <<(val)
22
+ if self.class.element_class && val.class == self.class.element_class
23
+ super(val)
24
+ else
25
+ super(self.class.element_class.new(val))
26
+ end
27
+ end
28
+
29
+ def each(&block)
30
+ yield __getobj__.each(&block)
31
+ end
32
+ end
33
+
34
+ class TypeCaster < ActiveRecord::Type::Value
35
+ include ::ActiveRecord::Type::Mutable
36
+
37
+ def initialize(*args, target_klass:)
38
+ super(*args)
39
+
40
+ @target_klass = target_klass
41
+ end
42
+
43
+ def type
44
+ :array
45
+ end
46
+
47
+ def type_cast_from_user(value)
48
+ value.is_a?(@target_klass) ? @target_klass : @target_klass.new(value || {})
49
+ end
50
+
51
+ def type_cast_from_database(value)
52
+ value.present? ? @target_klass.new(JSON.parse(value)) : value
53
+ end
54
+
55
+ def type_cast_for_database(value)
56
+ if value.present?
57
+ value.map{ |element| element.try(:to_json) }
58
+ else
59
+ nil
60
+ end
61
+ end
62
+ end
63
+
64
+ module Mixin
65
+ def self.mixin_registry_key; :array_attributes end;
66
+
67
+ extend ::Trax::Model::Mixin
68
+ include ::Trax::Model::Attributes::Mixin
69
+
70
+ module ClassMethods
71
+ def array_attribute(attribute_name, **options, &block)
72
+ attributes_klass_name = "#{attribute_name}_attributes".classify
73
+ attributes_klass = const_set(attributes_klass_name, ::Class.new(::Trax::Model::Attributes[:array]::Value))
74
+ attributes_klass.instance_eval(&block)
75
+
76
+ attributes_klass.element_class = options[:of] if options.has_key?(:of)
77
+
78
+ trax_attribute_fields[:array] ||= {}
79
+ trax_attribute_fields[:array][attribute_name] = attributes_klass
80
+
81
+ attribute(attribute_name, ::Trax::Model::Attributes[:array]::TypeCaster.new(target_klass: attributes_klass))
82
+
83
+ # self.default_value_for(attribute_name) { self.class.element_class.new }
84
+ # self.validates(attribute_name, :json_attribute => true)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,32 @@
1
+ require 'hashie/extensions/ignore_undeclared'
2
+
3
+ module Trax
4
+ module Model
5
+ module Attributes
6
+ module Types
7
+ class Enum < ::Trax::Model::Attributes::Type
8
+ class TypeCaster < ActiveRecord::Type::Integer
9
+ end
10
+
11
+ module Mixin
12
+ def self.mixin_registry_key; :enum_attributes end;
13
+
14
+ extend ::Trax::Model::Mixin
15
+ include ::Trax::Model::Attributes::Mixin
16
+ include ::Trax::Model::Enum
17
+
18
+ module ClassMethods
19
+ def enum_attribute(attribute_name, values:, **options, &block)
20
+ attribute(attribute_name, ::Trax::Model::Attributes[:enum]::TypeCaster.new)
21
+
22
+ options.delete(:validates) if options.key?(:validates)
23
+
24
+ as_enum(attribute_name, values, **options)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,76 @@
1
+ require 'hashie/extensions/ignore_undeclared'
2
+
3
+ module Trax
4
+ module Model
5
+ module Attributes
6
+ module Types
7
+ class Json < ::Trax::Model::Attributes::Type
8
+ class Value < ::Trax::Model::Struct
9
+ def self.permitted_keys
10
+ @permitted_keys ||= properties.map(&:to_sym)
11
+ end
12
+
13
+ def inspect
14
+ self.to_hash.inspect
15
+ end
16
+ end
17
+
18
+ class TypeCaster < ActiveRecord::Type::Value
19
+ include ::ActiveRecord::Type::Mutable
20
+
21
+ def initialize(*args, target_klass:)
22
+ super(*args)
23
+
24
+ @target_klass = target_klass
25
+ end
26
+
27
+ def type
28
+ :json
29
+ end
30
+
31
+ def type_cast_from_user(value)
32
+ value.is_a?(@target_klass) ? @target_klass : @target_klass.new(value || {})
33
+ end
34
+
35
+ def type_cast_from_database(value)
36
+ value.present? ? @target_klass.new(JSON.parse(value)) : value
37
+ end
38
+
39
+ def type_cast_for_database(value)
40
+ value.present? ? value.to_hash.to_json : nil
41
+ end
42
+ end
43
+
44
+ module Mixin
45
+ def self.mixin_registry_key; :json_attributes end;
46
+
47
+ extend ::Trax::Model::Mixin
48
+ include ::Trax::Model::Attributes::Mixin
49
+
50
+ included do
51
+ class_attribute :json_attribute_fields
52
+
53
+ self.json_attribute_fields = ::ActiveSupport::HashWithIndifferentAccess.new
54
+ end
55
+
56
+ module ClassMethods
57
+ def json_attribute(attribute_name, **options, &block)
58
+ attributes_klass_name = "#{attribute_name}_attributes".classify
59
+ attributes_klass = const_set(attributes_klass_name, ::Class.new(::Trax::Model::Attributes[:json]::Value))
60
+ attributes_klass.instance_eval(&block)
61
+
62
+ trax_attribute_fields[:json] ||= {}
63
+ trax_attribute_fields[:json][attribute_name] = attributes_klass
64
+
65
+ attribute(attribute_name, ::Trax::Model::Attributes[:json]::TypeCaster.new(target_klass: attributes_klass))
66
+
67
+ self.default_value_for(attribute_name) { {} }
68
+ self.validates(attribute_name, :json_attribute => true) unless options.key?(:validate) && !options[:validate]
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end