trax_model 0.0.91 → 0.0.92

Sign up to get free protection for your applications and to get access to all the features.
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