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 +4 -4
- data/lib/trax/core/concern.rb +20 -18
- data/lib/trax/core/configuration.rb +63 -23
- data/lib/trax/core/definition.rb +6 -0
- data/lib/trax/core/eager_autoload_namespace.rb +0 -8
- data/lib/trax/core/errors.rb +17 -1
- data/lib/trax/core/ext/array.rb +26 -0
- data/lib/trax/core/ext/class.rb +10 -0
- data/lib/trax/core/ext/hash.rb +50 -0
- data/lib/trax/core/ext/is.rb +21 -0
- data/lib/trax/core/ext/object.rb +8 -2
- data/lib/trax/core/ext/string.rb +4 -0
- data/lib/trax/core/ext/symbol.rb +6 -0
- data/lib/trax/core/ext/uri.rb +9 -0
- data/lib/trax/core/inheritance_hooks.rb +56 -0
- data/lib/trax/core/primitives/enum.rb +219 -0
- data/lib/trax/core/primitives/enum_value.rb +56 -0
- data/lib/trax/core.rb +11 -2
- data/lib/trax_core/version.rb +1 -1
- data/spec/spec_helper.rb +0 -1
- data/spec/support/category_enum.rb +6 -0
- data/spec/support/inheritance_chain_namespace.rb +15 -0
- data/spec/support/some_mixin.rb +26 -0
- data/spec/trax/array_spec.rb +13 -0
- data/spec/trax/core/concern_spec.rb +15 -0
- data/spec/trax/core/ext/array_spec.rb +11 -0
- data/spec/trax/core/ext/class_spec.rb +12 -0
- data/spec/trax/core/ext/object_spec.rb +1 -1
- data/spec/trax/core/ext/uri_spec.rb +15 -0
- data/spec/trax/core/inheritance_spec.rb +0 -0
- data/spec/trax/enum_spec.rb +69 -0
- data/spec/trax/hash_spec.rb +90 -0
- data/trax_core.gemspec +7 -7
- metadata +32 -102
- data/lib/trax/array.rb +0 -7
- data/lib/trax/core/inheritance.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6d1154c6a3219971c25e70ac2c4a820f313740d
|
4
|
+
data.tar.gz: ba70a2bd38733dc7c401d4750e1ce4f86313df9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c3ef17bf573140d83ab0d9f7f67de7d3d6c70174f28fca5db8c38cfb2fa19f7fc06c0be3165499e55820773360dd2769e75313c758c9e121aed3cb3067ef2a2
|
7
|
+
data.tar.gz: df4bb2354da8d72a729e951193dbe2d640c8d4b6c6b6a8ebd4e446025d726858e68a0802aa2325a425795125d0bf2c2e4e5026467df66c1473a1cdbaebb49cb8
|
data/lib/trax/core/concern.rb
CHANGED
@@ -1,47 +1,49 @@
|
|
1
1
|
module Trax
|
2
2
|
module Core
|
3
3
|
module Concern
|
4
|
-
def
|
5
|
-
|
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
|
-
|
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
|
-
|
21
|
-
|
19
|
+
base
|
20
|
+
end
|
22
21
|
|
23
|
-
|
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
|
-
|
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
|
-
|
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
|
13
|
-
|
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
|
-
|
43
|
-
|
44
|
-
instance_variable_set("@#{attr_name}", value)
|
38
|
+
options_module.module_eval do
|
39
|
+
attr_reader(attr_name)
|
45
40
|
|
46
|
-
|
47
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
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
|
@@ -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
|
data/lib/trax/core/errors.rb
CHANGED
@@ -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
|
data/lib/trax/core/ext/object.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
require "active_support/core_ext/object/try"
|
2
|
-
|
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
|
-
|
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
|
data/lib/trax/core/ext/string.rb
CHANGED
@@ -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
|