trax_core 0.0.71 → 0.0.72

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 00148fce6abf94b4bae0f495890d58d637c7ef7c
4
- data.tar.gz: 6b997761c5627bef815cadab245859c82b08e1d1
3
+ metadata.gz: c6d1154c6a3219971c25e70ac2c4a820f313740d
4
+ data.tar.gz: ba70a2bd38733dc7c401d4750e1ce4f86313df9c
5
5
  SHA512:
6
- metadata.gz: 5135d5b5f0937409b9149c47c9b38fc813192d7b0bd3637a10181ceea66aabc5f833ed60bad04aec99c380265dc0462d58eed83d177b9a67910d4fd0656aa234
7
- data.tar.gz: fd4d5910f334c643e5b1120098f1d601dab9a1facd9473359f1211df0dbeda18ffee17ac95408c91f3b3e753f187f0d8ba204010873fd7d62df382d80dc6fc49
6
+ metadata.gz: 9c3ef17bf573140d83ab0d9f7f67de7d3d6c70174f28fca5db8c38cfb2fa19f7fc06c0be3165499e55820773360dd2769e75313c758c9e121aed3cb3067ef2a2
7
+ data.tar.gz: df4bb2354da8d72a729e951193dbe2d640c8d4b6c6b6a8ebd4e446025d726858e68a0802aa2325a425795125d0bf2c2e4e5026467df66c1473a1cdbaebb49cb8
@@ -1,47 +1,49 @@
1
1
  module Trax
2
2
  module Core
3
3
  module Concern
4
- def included(base = nil, &block)
5
- super(base, &block)
4
+ def self.extended(base)
5
+ base.extend(::ActiveSupport::Concern)
6
6
 
7
7
  trace = ::TracePoint.new(:end) do |tracepoint|
8
- if tracepoint.self == base
9
- trace.disable
10
-
11
- if self.instance_variable_defined?(:@_after_included_block)
12
- base.instance_eval(&self.instance_variable_get(:@_after_included_block))
8
+ if tracepoint.self.singleton_class.included_modules.first == base
9
+ if base.instance_variable_defined?(:@_after_extended_block)
10
+ tracepoint.self.module_exec(base, &base.instance_variable_get(:@_after_extended_block))
13
11
  end
12
+
13
+ trace.disable
14
14
  end
15
15
  end
16
16
 
17
17
  trace.enable
18
- end
19
18
 
20
- def self.extended(base)
21
- base.extend(::ActiveSupport::Concern)
19
+ base
20
+ end
22
21
 
23
- super(base)
22
+ def included(base = nil, &block)
23
+ super(base, &block) if defined?(super)
24
24
 
25
25
  trace = ::TracePoint.new(:end) do |tracepoint|
26
26
  if tracepoint.self == base
27
- trace.disable
28
-
29
- if base.instance_variable_defined?(:@_after_extended_block)
30
- base.instance_variable_get(:@_after_extended_block).call
27
+ if self.instance_variable_defined?(:@_after_included_block)
28
+ base.instance_eval(&self.instance_variable_get(:@_after_included_block))
31
29
  end
30
+
31
+ trace.disable
32
32
  end
33
33
  end
34
34
 
35
35
  trace.enable
36
- end
37
36
 
38
- def after_extended(&block)
39
- self.instance_variable_set(:@_after_extended_block, block)
37
+ base
40
38
  end
41
39
 
42
40
  def after_included(&block)
43
41
  self.instance_variable_set(:@_after_included_block, block)
44
42
  end
43
+
44
+ def after_extended(&block)
45
+ self.instance_variable_set(:@_after_extended_block, block)
46
+ end
45
47
  end
46
48
  end
47
49
  end
@@ -9,52 +9,92 @@ module Trax
9
9
 
10
10
  class_attribute :source
11
11
 
12
- def initialize
13
- set_default_values
14
-
15
- yield self if block_given?
16
-
17
- raise_errors unless self.valid?
18
- end
19
-
20
- def set_default_values
21
- self.class.configurable_options.select{|attr_name, hash| hash.key?(:default) }.each_pair do |attr_name,hash|
22
- __send__("#{attr_name}=", hash[:default])
23
- end
12
+ def self.after_configured(&block)
13
+ self.instance_variable_set("@_after_configured_block", block)
24
14
  end
25
15
 
26
16
  def self.inherited(subklass)
27
17
  super(subklass)
28
18
 
19
+ subklass.class_attribute :options_module
20
+ subklass.options_module = subklass.const_set("Options", ::Module.new)
21
+ subklass.include(subklass.options_module)
22
+
29
23
  subklass.class_attribute :configurable_options
30
24
  subklass.configurable_options = {}
31
25
  end
32
26
 
27
+ #the reason for defining the methods in the options module which gets
28
+ #dynamically created is to preserve the inheritance chain
29
+ #so def something= can be overwritten, and call super, an example is in
30
+ #Trax::Model::UniqueId
31
+ #there probably is a cleaner way to do it though.
33
32
  def self.option(attr_name, options = {})
34
- attr_accessor attr_name
35
-
36
33
  validates_presence_of(attr_name) if(options.key?(:required))
37
-
38
34
  if(options.key?(:validates))
39
35
  validates(attr_name, options[:validates])
40
36
  end
41
37
 
42
- define_method("#{attr_name}=") do |val|
43
- value = options.key?(:setter) ? options[:setter].call(val) : val
44
- instance_variable_set("@#{attr_name}", value)
38
+ options_module.module_eval do
39
+ attr_reader(attr_name)
45
40
 
46
- raise_errors unless self.valid?
47
- end
41
+ define_method(:"#{attr_name}=") do |val|
42
+ value = options.key?(:setter) ? options[:setter].call(val) : val
43
+ instance_variable_set("@#{attr_name}", value)
44
+
45
+ raise_errors unless self.valid?
46
+ end
48
47
 
49
- if(options.key?(:getter))
50
- define_method(attr_name) do |val|
51
- options[:getter].call(val)
48
+ if(options.key?(:getter))
49
+ define_method(attr_name) do |val|
50
+ options[:getter].call(val)
51
+ end
52
52
  end
53
53
  end
54
54
 
55
55
  self.configurable_options[attr_name] = options
56
56
  end
57
57
 
58
+ def self.klass(&block)
59
+ #so we can properly resolve super lookups, we define new module and include
60
+ mod = ::Module.new
61
+ mod.module_eval(&block)
62
+ include(mod)
63
+ end
64
+
65
+ def initialize
66
+ set_default_values
67
+
68
+ yield self if block_given?
69
+
70
+ raise_errors unless self.valid?
71
+
72
+ self.class.instance_variable_get("@_after_configured_block").call(self) if self.class.instance_variable_defined?("@_after_configured_block")
73
+ end
74
+
75
+ def compact
76
+ cached_hash.compact
77
+ end
78
+
79
+ def cached_hash
80
+ @cached_hash ||= hash
81
+ end
82
+
83
+ def hash
84
+ configurable_options.keys.each_with_object({}) do |key, result|
85
+ result[key] = __send__(key)
86
+ end
87
+ end
88
+
89
+ def set_default_values
90
+ self.class.configurable_options.select{|attr_name, hash| hash.key?(:default) }.each_pair do |attr_name, hash|
91
+ parent_context = self.class.parent_name.try(:constantize) if self.class.try(:parent_name)
92
+
93
+ default_value_for_option = hash[:default].is_a?(Proc) ? self.instance_exec(parent_context, &hash[:default]) : hash[:default]
94
+ __send__("#{attr_name}=", default_value_for_option)
95
+ end
96
+ end
97
+
58
98
  def merge!(options = {})
59
99
  options.each_pair{ |k,v| __send__("#{k}=", v) }
60
100
  end
@@ -0,0 +1,6 @@
1
+ module Trax
2
+ module Core
3
+ class Definition < ::Hashie::Mash
4
+ end
5
+ end
6
+ end
@@ -6,16 +6,8 @@ module Trax
6
6
  source_file_path = caller[0].partition(":")[0]
7
7
 
8
8
  base.module_eval do
9
- extend ::ActiveSupport::Autoload
10
-
11
9
  @eager_autoload_filepath = source_file_path
12
10
  end
13
-
14
- base.autoload_class_names.each do |klass|
15
- base.autoload :"#{klass}"
16
- end
17
-
18
- base.eager_load!
19
11
  end
20
12
 
21
13
  def all
@@ -72,7 +72,7 @@ module Trax
72
72
 
73
73
  attr_reader :arguments_instance
74
74
 
75
- def initialize(_attributes = {})
75
+ def initialize(**_attributes)
76
76
  @arguments_instance = self.class.permitted_arguments_klass.new(_attributes)
77
77
 
78
78
  super(message)
@@ -103,6 +103,22 @@ module Trax
103
103
  "registry. Registered mixins were #{mixin_namespace.mixin_registry.keys.join(', ')} \n"
104
104
  }
105
105
  end
106
+
107
+ class DuplicateEnumValue < ::Trax::Core::Errors::Base
108
+ argument :value
109
+ argument :klass
110
+ message {
111
+ "#{klass} duplicate value #{value}"
112
+ }
113
+ end
114
+
115
+ class InvalidEnumValue < ::Trax::Core::Errors::Base
116
+ argument :field
117
+ argument :value
118
+ message {
119
+ "#{field} Invalid enum value for #{value} "
120
+ }
121
+ end
106
122
  end
107
123
  end
108
124
  end
@@ -0,0 +1,26 @@
1
+ class Array
2
+ #inspired by: http://thepugautomatic.com/2014/11/array-to-proc-for-hash-access/
3
+ def to_proc
4
+ ->(hash_or_object) {
5
+ if hash_or_object.is_a?(::Hash)
6
+ length == 1 ? hash_or_object[first] : hash_or_object.values_at(*self)
7
+ else
8
+ length == 1 ? hash_or_object.__send__(first) : self.each_with_object({}){ |method_name,result|
9
+ result[method_name] = hash_or_object.__send__(method_name)
10
+ }
11
+ end
12
+ }
13
+ end
14
+
15
+ def flat_compact_uniq!
16
+ self.flatten!
17
+ self.compact!
18
+ self.uniq!
19
+ self
20
+ end
21
+ alias :flatten_compact_uniq! :flat_compact_uniq!
22
+
23
+ def to_single_quoted_list
24
+ "\'#{self.join("', '")}\'"
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ class Class
2
+ def superclasses_until(klass, bottom_klass=self, superclass_chain = [])
3
+ if bottom_klass.superclass != klass
4
+ superclass_chain.unshift(bottom_klass.superclass)
5
+ return superclasses_until(klass, bottom_klass.superclass, superclass_chain)
6
+ else
7
+ return superclass_chain
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,50 @@
1
+ class Hash
2
+ ## Returns selected keys, named or renamed as specified
3
+ # myproduct = {:name => "something", :price => "20"}
4
+ # liability = myproduct.tap(&{:cost => :price})
5
+ # liability[:cost] == 20
6
+ ## Note: Tap only works where source is a hash object, so use as otherwise
7
+ # (because tap always returns the object you are tapping)
8
+ # myproduct = ::OpenStruct.new({:name => "something", :price => "20"})
9
+ # liability.as!(&{:cost => :price})
10
+ # liability[:cost] == 20
11
+ #
12
+ # Transforming values:
13
+ # Pass a hash as the value with the key being the source key/method
14
+ # myproduct = ::OpenStruct.new({:name => "something", :price => "20"})
15
+ # my_sale_product = myproduct.as!(&{:sale_price => {:price => ->(val){ val / 2 } } })
16
+ # my_sale_product[:sale_price] == 10
17
+
18
+ def to_proc
19
+ ->(hash_or_object) {
20
+ new_hash = {}
21
+
22
+ if hash_or_object.is_a?(::Hash)
23
+ self.each_pair do |k,v|
24
+ if v.is_a?(Hash)
25
+ new_hash[k] = v.values.first.call(hash_or_object[v.keys.first])
26
+ elsif v.is_a?(Proc)
27
+ new_hash[k] = v.call(hash_or_object[k])
28
+ else
29
+ new_hash[k] = hash_or_object[v]
30
+ end
31
+ end
32
+
33
+ hash_or_object.keys.map{ |k| hash_or_object.delete(k) }
34
+ hash_or_object.merge!(new_hash)
35
+ else
36
+ self.each_pair do |k,v|
37
+ if v.is_a?(Hash)
38
+ new_hash[k] = v.values.first.call(hash_or_object.__send__(v.keys.first))
39
+ elsif v.is_a?(Proc)
40
+ new_hash[k] = v.call(hash_or_object.__send__(k))
41
+ else
42
+ new_hash[k] = hash_or_object.__send__(v)
43
+ end
44
+ end
45
+ end
46
+
47
+ return new_hash
48
+ }
49
+ end
50
+ end
@@ -0,0 +1,21 @@
1
+ class Is
2
+ def self.truthy?(val)
3
+ [true, false].include?(val)
4
+ end
5
+
6
+ def self.numeric?(val)
7
+ val.is_a?(::Numeric)
8
+ end
9
+
10
+ def self.string?(val)
11
+ val.is_a?(::String)
12
+ end
13
+
14
+ def self.symbol?(val)
15
+ val.is_a?(::Symbol)
16
+ end
17
+
18
+ def self.symbolic?(val)
19
+ val.is_a?(::String) || val.is_a?(::Symbol)
20
+ end
21
+ end
@@ -1,6 +1,10 @@
1
1
  require "active_support/core_ext/object/try"
2
- require 'pry'
2
+
3
3
  class Object
4
+ def as!
5
+ yield self
6
+ end
7
+
4
8
  # Defines a Configuration Class within a target module namespace, or nested class
5
9
  # i.e. configuration_for(::Ecommerce::Cart) will define
6
10
  # Ecommerce::Cart::Configuration class, inherited form Trax::Core::Configuration
@@ -45,8 +49,10 @@ class Object
45
49
 
46
50
  def remove_instance_variables(*args)
47
51
  args.map{ |ivar_name|
48
- remove_instance_variable(:"@#{ivar_name}") if instance_variable_defined?(:"@#{ivar_name}")
52
+ ivar_name = ivar_name.ivar? ? ivar_name : :"@#{ivar_name}"
53
+ remove_instance_variable(ivar_name) if instance_variable_defined?(ivar_name)
49
54
  }
55
+
50
56
  self
51
57
  end
52
58
  alias_method :reset_instance_variables, :remove_instance_variables
@@ -1,4 +1,8 @@
1
1
  class String
2
+ def symbolize
3
+ self.try_chain(:demodulize, :underscore, :to_sym)
4
+ end
5
+
2
6
  def translate(*args)
3
7
  I18n.translate(self.underscore, *args)
4
8
  end
@@ -0,0 +1,6 @@
1
+ class Symbol
2
+ def is_ivar?
3
+ id2name.starts_with?("@")
4
+ end
5
+ alias :ivar? :is_ivar?
6
+ end
@@ -0,0 +1,9 @@
1
+ module URIExtensions
2
+ def join(*args)
3
+ self + args.map{ |arg| arg.is_a?(::String) ? arg : arg.to_s }.join("/")
4
+ end
5
+ end
6
+
7
+ class URI::Generic
8
+ include URIExtensions
9
+ end
@@ -0,0 +1,56 @@
1
+ module Trax
2
+ module Core
3
+ module InheritanceHooks
4
+ extend ::ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def inherited(subklass)
8
+ super(subklass)
9
+
10
+ if self.instance_variable_defined?(:@_on_inherited_block)
11
+ subklass.instance_eval(&self.instance_variable_get(:@_on_inherited_block))
12
+ end
13
+
14
+ if subklass.class == Class
15
+ #this supports anonymous classes created with a block passed, i.e.
16
+ # Class.new(Enum, &Proc.new{VAL=1})
17
+ # otherwise Class.new wont be caught by tracepoint statement below
18
+ trace = ::TracePoint.new(:b_return) do |tracepoint|
19
+ if tracepoint.self.class == Class
20
+ if self.instance_variable_defined?(:@_after_inherited_block)
21
+ subklass.instance_eval(&self.instance_variable_get(:@_after_inherited_block))
22
+ end
23
+
24
+ trace.disable
25
+ end
26
+ end
27
+
28
+ trace.enable
29
+ else
30
+ trace = ::TracePoint.new(:end) do |tracepoint|
31
+ if tracepoint.self == subklass
32
+ if self.instance_variable_defined?(:@_after_inherited_block)
33
+ subklass.instance_eval(&self.instance_variable_get(:@_after_inherited_block))
34
+ end
35
+
36
+ trace.disable
37
+ end
38
+ end
39
+
40
+ trace.enable
41
+
42
+ self
43
+ end
44
+ end
45
+
46
+ def after_inherited(&block)
47
+ self.instance_variable_set(:@_after_inherited_block, block)
48
+ end
49
+
50
+ def on_inherited(&block)
51
+ self.instance_variable_set(:@_on_inherited_block, block)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,219 @@
1
+ # require 'trax/core/inheritance_hooks'
2
+ # require 'active_model/attribute_methods'
3
+ ### Examples
4
+ # ProductCategory < Enum
5
+ # CLOTHING = 1
6
+ # SHOES = 2
7
+ # ACCESSORIES = 3
8
+ # end
9
+ # ProductCategory.keys => [:clothing, :shoes, :accessories]
10
+
11
+ # StoreYearlyRevenue < Enum
12
+ # :'0_100000' = 1
13
+ # :'100000_999999' = 2
14
+ # :'1000000_99999999' = 3
15
+ # end
16
+
17
+ ### Accepts either an integer or the name when setting a value
18
+ # ProductCategory.new(1) => #{name: :clothing, :value => 1}
19
+
20
+ class Enum < SimpleDelegator
21
+ class_attribute :allow_nil, :raise_on_invalid
22
+
23
+ ### Class Methods ###
24
+ def self.define_enum_value(const_name, val=nil)
25
+ name = "#{const_name}".underscore.to_sym
26
+ const_name = name.to_s.camelize
27
+ val = (self._values_hash.length + 1) if val.nil?
28
+
29
+ raise ::Trax::Core::Errors::DuplicateEnumValue.new(:klass => self.class.name, :value => const_name) if self === name
30
+ raise ::Trax::Core::Errors::DuplicateEnumValue.new(:klass => self.class.name, :value => val) if self === val
31
+
32
+ value_klass = self.const_set(const_name, Class.new(::EnumValue){
33
+ self.tag = name
34
+ self.value = val
35
+ })
36
+
37
+ self._values_hash[val] = value_klass
38
+ self._names_hash[name] = value_klass
39
+ end
40
+
41
+ def self.[](val)
42
+ if ::Is.numeric?(val)
43
+ self._values_hash[val]
44
+ elsif ::Is.symbolic?(val)
45
+ val = val.to_sym if val.is_a?(String)
46
+ self._names_hash[val]
47
+ elsif val.superclass.name == "EnumValue"
48
+ val = val.to_sym
49
+ self._names_hash[val]
50
+ end
51
+ end
52
+
53
+ def self.as_json(options={})
54
+ choice.to_s
55
+ end
56
+
57
+ def self.choices
58
+ @choices ||= self._values_hash.values
59
+ end
60
+
61
+ def self.formatted_choices
62
+ @formatted_choices ||= choices.each_with_object({}) do |choice, hash|
63
+ hash[choice.to_i] = choice.to_s
64
+ end
65
+ end
66
+
67
+ def self.select_values(*args)
68
+ args.flat_compact_uniq!
69
+ args.map{|arg| self[arg].to_i }
70
+ end
71
+
72
+ def self.define(*args)
73
+ define_enum_value(*args)
74
+ end
75
+
76
+ #define multiple values if its iterable
77
+ def self.define_values(*args)
78
+ args.each_with_index do |arg, i|
79
+ define_enum_value(arg, (i + 1))
80
+ end
81
+ end
82
+
83
+ def self.each(&block)
84
+ keys.each(&block)
85
+ end
86
+
87
+ def self.each_pair(&block)
88
+ self._names_hash.each_pair(&block)
89
+ end
90
+
91
+ def self.keys
92
+ _names_hash.keys
93
+ end
94
+
95
+ def self.key?(name)
96
+ _names_hash.key?(name)
97
+ end
98
+
99
+ def self.names
100
+ _names_hash.values
101
+ end
102
+
103
+ def self.no_raise_mode?
104
+ !raise_on_invalid
105
+ end
106
+
107
+ def self.valid_name?(val)
108
+ _names_as_strings.include?(val)
109
+ end
110
+
111
+ def self.valid_value?(val)
112
+ values.include?(val)
113
+ end
114
+
115
+ #because calling valid_value? in the define_enum_value method is unclear
116
+ def self.value?(val)
117
+ valid_value?(val)
118
+ end
119
+
120
+ def self.values
121
+ _names_hash.values.map(&:to_i)
122
+ end
123
+
124
+ def self.===(val)
125
+ _names_hash.values.any?{|v| v === val }
126
+ end
127
+
128
+ def self.type
129
+ :enum
130
+ end
131
+
132
+ def self.to_schema
133
+ ::Trax::Core::Definition.new(
134
+ :name => self.name.demodulize.underscore,
135
+ :source => self.name,
136
+ :type => :enum,
137
+ :choices => choices.map(&:to_schema),
138
+ :values => keys
139
+ )
140
+ end
141
+
142
+ class << self
143
+ alias :enum_value :define_enum_value
144
+ alias :define :define_enum_value
145
+ attr_accessor :_values_hash
146
+ attr_accessor :_names_hash
147
+ attr_accessor :_names_as_strings
148
+ end
149
+
150
+ ### Hooks ###
151
+ def self.inherited(subklass)
152
+ subklass.instance_variable_set(:@_values_hash, ::Hash.new)
153
+ subklass.instance_variable_set(:@_names_hash, ::Hash.new)
154
+ subklass.allow_nil = false
155
+ subklass.raise_on_invalid = false
156
+ end
157
+
158
+ ### Instance Methods ###
159
+ attr_reader :choice
160
+
161
+ def initialize(val)
162
+ self.choice = val unless val.nil? && self.class.allow_nil
163
+ end
164
+
165
+ def current_index
166
+ self.class.names.index(choice)
167
+ end
168
+
169
+ def choice=(val)
170
+ @choice = valid_choice?(val) ? self.class[val] : nil
171
+
172
+ raise ::Trax::Core::Errors::InvalidEnumValue.new(
173
+ :field => self.class.name,
174
+ :value => val
175
+ ) if self.class.raise_on_invalid && !@choice
176
+
177
+ @choice
178
+ end
179
+
180
+ def __getobj__
181
+ @choice || nil
182
+ end
183
+
184
+ def next_value
185
+ return choice if self.class.names.length == current_index
186
+ self.class.names[(current_index + 1)]
187
+ end
188
+
189
+ def next_value?
190
+ !(current_index == (self.class.names.length - 1))
191
+ end
192
+
193
+ #set choice if next value exists, return selected choi
194
+ def select_next_value
195
+ self.choice = next_value.to_sym if next_value?
196
+ self
197
+ end
198
+
199
+ def select_previous_value
200
+ self.choice = previous_value.to_sym if previous_value?
201
+ self
202
+ end
203
+
204
+ def previous_value
205
+ self.class.names[(current_index - 1)]
206
+ end
207
+
208
+ def previous_value?
209
+ !!current_index
210
+ end
211
+
212
+ def to_s
213
+ choice.to_s
214
+ end
215
+
216
+ def valid_choice?(val)
217
+ self.class === val
218
+ end
219
+ end