class_kit 0.9.1 → 0.10.0

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
  SHA256:
3
- metadata.gz: 174b8ba8709d3d55964c17cb86fb820b786e03a3bf4c17fa11b2db2c07ebf3f4
4
- data.tar.gz: 1c1a03980781a37881a209e47cf596529dad0ce1a41dc6d301f91e295fd60e28
3
+ metadata.gz: adc7d06961d743b02621fcdd08fd15e284326e8af5356b0d99c4c7bc72c085d5
4
+ data.tar.gz: cf0fd671ff222e614ec865d1e0521ef68093f3742ce994b0f93874f107f583b5
5
5
  SHA512:
6
- metadata.gz: df7de4121b05e773056d8ef4af2b7aefde3a47b6dc42ff2cf2d711ba841c1b2e79fcc978a278e208f355cadc0dba12e8906b390582dea2bdfa4e2952557d86a7
7
- data.tar.gz: 2709a0c45a4e95f7bf79675821f1ee0a009887688f47b3a013f2e326a38a9ec97a3e3f44a37b00b243d2f937427a405470a21886eaa2e9d92ec4dafe7a8eb3e7
6
+ metadata.gz: 56aa30b2d347e2cb6aa3451e0da1249df9ab83c58ef27df14b81ad24363aeaf2cf4c3bc270697e5b1f88c1a4f0d316019f271bb2f7c8ce3ea62cb6f29d683a9e
7
+ data.tar.gz: 6ce07544f9b67cd5c6da85cc8e97568ec4dc051b5797695e124bf463d1e0aa921e867ad6823b0b58f809212deb157e26eb3332e0665f0d0e4d544498611fe02c
@@ -1,6 +1,5 @@
1
1
  module ClassKit
2
2
  class AttributeHelper
3
-
4
3
  def self.instance
5
4
  @instance ||= ClassKit::AttributeHelper.new
6
5
  end
@@ -18,12 +17,12 @@ module ClassKit
18
17
  return @attribute_store[klass] if @attribute_store.key?(klass)
19
18
 
20
19
  attributes = []
21
- klass.ancestors.map do |k|
20
+ klass.ancestors.each do |k|
22
21
  hash = k.instance_variable_get(:@class_kit_attributes)
23
- if hash != nil
24
- hash.values.each do |a|
25
- attributes.push(a)
26
- end
22
+ next if hash.nil?
23
+
24
+ hash.each_value do |value|
25
+ attributes.push(value)
27
26
  end
28
27
  end
29
28
  attributes.compact!
@@ -8,15 +8,18 @@ module ClassKit
8
8
  default: nil,
9
9
  auto_init: false,
10
10
  alias_name: nil,
11
- meta: {})
12
- unless instance_variable_defined?(:@class_kit_attributes)
13
- instance_variable_set(:@class_kit_attributes, {})
14
- end
11
+ meta: {}
12
+ )
13
+ instance_variable_set(:@class_kit_attributes, {}) unless instance_variable_defined?(:@class_kit_attributes)
15
14
 
16
15
  attributes = instance_variable_get(:@class_kit_attributes)
17
16
 
18
- attributes[name] = {
17
+ getter = :"@#{name}"
18
+ setter = :"#{name}="
19
+
20
+ cka = {
19
21
  name: name,
22
+ setter: setter,
20
23
  type: type,
21
24
  one_of: one_of,
22
25
  collection_type: collection_type,
@@ -25,68 +28,104 @@ module ClassKit
25
28
  auto_init: auto_init,
26
29
  alias: alias_name,
27
30
  meta: meta
28
- }
29
-
30
- class_eval do
31
- define_method name do
31
+ }.freeze
32
+ attributes[name] = cka
32
33
 
33
- cka = ClassKit::AttributeHelper.instance.get_attribute(klass: self.class, name: name)
34
+ value_helper = ClassKit::ValueHelper.instance
34
35
 
35
- current_value = instance_variable_get(:"@#{name}")
36
+ # ========= Define attribute getter =========
37
+ if !default.nil? || auto_init
38
+ class_eval do
39
+ define_method name do
40
+ current_value = instance_variable_get(getter)
36
41
 
37
- if current_value.nil?
38
- if !cka[:default].nil?
39
- current_value = instance_variable_set(:"@#{name}", cka[:default])
40
- elsif cka[:auto_init]
41
- current_value = instance_variable_set(:"@#{name}", cka[:type].new)
42
+ if current_value.nil?
43
+ if !cka[:default].nil?
44
+ current_value = instance_variable_set(getter, cka[:default])
45
+ elsif cka[:auto_init]
46
+ current_value = instance_variable_set(getter, cka[:type].new)
47
+ end
42
48
  end
43
- end
44
49
 
45
- current_value
50
+ current_value
51
+ end
46
52
  end
47
- end
48
-
49
- class_eval do
50
- define_method "#{name}=" do |value|
51
- # get the attribute meta data
52
- cka = ClassKit::AttributeHelper.instance.get_attribute(klass: self.class, name: name)
53
-
54
- # verify if the attribute is allowed to be set to nil
55
- if value.nil? && cka[:allow_nil] == false
56
- raise ClassKit::Exceptions::InvalidAttributeValueError, "Attribute: #{name}, must not be nil."
53
+ else
54
+ # no default or auto_init: just return the variable
55
+ class_eval do
56
+ define_method(name) do
57
+ instance_variable_get(getter)
57
58
  end
59
+ end
60
+ end
58
61
 
59
- if !cka[:one_of].nil? && !value.nil?
60
- parsed_value =
61
- if value == true || value == false
62
- value
63
- elsif(/(true|t|yes|y|1)$/i === value.to_s.downcase)
64
- true
65
- elsif (/(false|f|no|n|0)$/i === value.to_s.downcase)
66
- false
62
+ # ========= Define attribute setter =========
63
+ # The methods are defined as lean as possible
64
+ # This is a bit harder to read at this level but it gets rid of unnecessary runtime checks
65
+ # 1. If one_of is specified, we check if the value matches any of the allowed types
66
+ if one_of
67
+ class_eval do
68
+ define_method "#{name}=" do |value|
69
+ if value.nil? && cka[:allow_nil] == false
70
+ raise ClassKit::Exceptions::InvalidAttributeValueError, "Attribute: #{name}, must not be nil."
67
71
  end
68
72
 
69
- if parsed_value != nil
70
- value = parsed_value
71
- else
73
+ value = if value.nil?
74
+ value
75
+ elsif [true, false].include?(value)
76
+ value
77
+ elsif Constants::BOOL_TRUE_RE.match?(value.to_s)
78
+ true
79
+ elsif Constants::BOOL_FALSE_RE.match?(value.to_s)
80
+ false
81
+ else
82
+ begin
83
+ t = cka[:one_of].detect { |t| value.is_a?(t) }
84
+ value = value_helper.parse(type: t, value: value)
85
+ rescue StandardError => e
86
+ raise ClassKit::Exceptions::InvalidAttributeValueError,
87
+ "Attribute: #{name}, must be of type: #{t}. Error: #{e}"
88
+ end
89
+ end
90
+
91
+ instance_variable_set(getter, value)
92
+ end
93
+ end
94
+ # 2. When the attribute is typed, we parse into the target type if needed
95
+ elsif type
96
+ class_eval do
97
+ define_method "#{name}=" do |value|
98
+ if value.nil?
99
+ if cka[:allow_nil] == false
100
+ raise ClassKit::Exceptions::InvalidAttributeValueError, "Attribute: #{name}, must not be nil."
101
+ end
102
+ elsif type == :bool || !value.is_a?(type)
72
103
  begin
73
- type = cka[:one_of].detect {|t| value.is_a?(t) }
74
- value = ClassKit::ValueHelper.instance.parse(type: type, value: value)
75
- rescue => e
76
- raise ClassKit::Exceptions::InvalidAttributeValueError, "Attribute: #{name}, must be of type: #{type}. Error: #{e}"
104
+ value = value_helper.parse(type: type, value: value)
105
+ rescue StandardError => e
106
+ raise ClassKit::Exceptions::InvalidAttributeValueError,
107
+ "Attribute: #{name}, must be of type: #{type}. Error: #{e}"
77
108
  end
78
109
  end
79
- end
80
110
 
81
- if !cka[:type].nil? && !value.nil? && (cka[:type] == :bool || !value.is_a?(cka[:type]))
82
- begin
83
- value = ClassKit::ValueHelper.instance.parse(type: cka[:type], value: value)
84
- rescue => e
85
- raise ClassKit::Exceptions::InvalidAttributeValueError, "Attribute: #{name}, must be of type: #{cka[:type]}. Error: #{e}"
86
- end
111
+ instance_variable_set(getter, value)
112
+ end
113
+ end
114
+ # 3. If untyped and we allow nil, simply set the variable
115
+ elsif allow_nil == true
116
+ class_eval do
117
+ define_method "#{name}=" do |value|
118
+ instance_variable_set(getter, value)
87
119
  end
120
+ end
121
+ # 4. In all other cases, only set the variable if non-nil
122
+ else
123
+ class_eval do
124
+ define_method "#{name}=" do |value|
125
+ raise ClassKit::Exceptions::InvalidAttributeValueError, "Attribute: #{name}, must not be nil." if value.nil?
88
126
 
89
- instance_variable_set(:"@#{name}", value)
127
+ instance_variable_set(getter, value)
128
+ end
90
129
  end
91
130
  end
92
131
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ClassKit
4
+ module Constants
5
+ # Shared constants, to avoid re-creating them on each call to helper methods.
6
+ BOOL_TRUE_RE = /\A(?:true|t|yes|y|1)\z/i
7
+ BOOL_FALSE_RE = /\A(?:false|f|no|n|0)\z/i
8
+ end
9
+ end
@@ -1,39 +1,19 @@
1
1
  module ClassKit
2
2
  class ValueHelper
3
-
4
3
  def self.instance
5
4
  @@instance ||= new
6
5
  end
7
6
 
8
7
  def parse(type:, value:)
9
- if type == Time
10
- if value.is_a?(Time)
11
- value
12
- elsif value.is_a?(Integer) || value.is_a?(Float) || value.is_a?(BigDecimal)
13
- Time.at(value)
14
- else
15
- Time.parse(value)
16
- end
17
- elsif type == Date
18
- if value.is_a?(Date)
19
- value
20
- else
21
- Date.parse(value)
22
- end
23
- elsif type == DateTime
24
- if value.is_a?(DateTime)
25
- value
26
- else
27
- DateTime.parse(value)
28
- end
29
- elsif type == :bool
30
- if value == true || value == false
31
- value
32
- elsif(/(true|t|yes|y|1)$/i === value.to_s.downcase)
8
+ if type == :bool
9
+ return value if value == true || value == false
10
+
11
+ s = value.to_s
12
+ if Constants::BOOL_TRUE_RE.match?(s)
33
13
  true
34
- elsif (/(false|f|no|n|0)$/i === value.to_s.downcase)
14
+ elsif Constants::BOOL_FALSE_RE.match?(s)
35
15
  false
36
- elsif value != nil
16
+ elsif !value.nil?
37
17
  raise 'Unable to parse bool'
38
18
  end
39
19
  elsif type == Integer
@@ -44,26 +24,41 @@ module ClassKit
44
24
  if value.is_a?(BigDecimal)
45
25
  value
46
26
  else
47
- value = value.to_s
48
- raise 'Unable to parse BigDecimal' unless value =~ /\A-?\d+(\.\d*)?/
49
- BigDecimal(value)
27
+ s = value.to_s
28
+ raise 'Unable to parse BigDecimal' unless s =~ /\A-?\d+(\.\d*)?/
29
+
30
+ BigDecimal(s)
50
31
  end
51
32
  elsif type == String
52
33
  String(value)
34
+ elsif type == Time
35
+ if value.is_a?(Time)
36
+ value
37
+ elsif value.is_a?(Integer) || value.is_a?(Float) || value.is_a?(BigDecimal)
38
+ Time.at(value)
39
+ else
40
+ Time.parse(value)
41
+ end
42
+ elsif type == Date
43
+ value.is_a?(Date) ? value : Date.parse(value)
44
+ elsif type == DateTime
45
+ value.is_a?(DateTime) ? value : DateTime.parse(value)
53
46
  elsif type == Regexp
54
47
  Regexp.new(value)
55
48
  elsif type == Hash
56
49
  raise 'Unable to parse Hash' unless value.is_a?(Hash)
50
+
57
51
  value
58
52
  elsif type == Array
59
53
  raise 'Unable to parse Array' unless value.is_a?(Array)
54
+
60
55
  value
61
56
  elsif type.include?(ClassKit::CustomType)
62
57
  type.parse_assign(value)
63
58
  else
64
59
  raise 'Unable to parse'
65
60
  end
66
- rescue => e
61
+ rescue StandardError => e
67
62
  raise ClassKit::Exceptions::InvalidParseValueError,
68
63
  "Unable to parse value: #{value} into type: #{type}. Error: #{e}"
69
64
  end
@@ -1,5 +1,5 @@
1
1
  # Namespace
2
2
  module ClassKit
3
3
  # :nodoc:
4
- VERSION = '0.9.1'
4
+ VERSION = '0.10.0'
5
5
  end
data/lib/class_kit.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require_relative 'class_kit/constants'
1
2
  require_relative 'class_kit/class_methods'
2
3
  require_relative 'class_kit/exceptions'
3
4
  require_relative 'class_kit/attribute_helper'
@@ -10,4 +11,3 @@ require 'json'
10
11
  require 'date'
11
12
  require 'bigdecimal'
12
13
  require 'time'
13
-
metadata CHANGED
@@ -1,45 +1,45 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: class_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sage One
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-02-28 00:00:00.000000000 Z
11
+ date: 2026-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
14
+ name: rake
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '2'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '2'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
28
+ name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rspec
42
+ name: rubocop
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -132,6 +132,7 @@ files:
132
132
  - lib/class_kit.rb
133
133
  - lib/class_kit/attribute_helper.rb
134
134
  - lib/class_kit/class_methods.rb
135
+ - lib/class_kit/constants.rb
135
136
  - lib/class_kit/custom_type.rb
136
137
  - lib/class_kit/exceptions.rb
137
138
  - lib/class_kit/exceptions/attribute_not_found_error.rb