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