u-struct 0.6.0 → 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: 52450d53b7accc5aa4c83682dfc6557d3f5fa4d7879648c189701198548e0ace
4
- data.tar.gz: 4a25f913523f7aa9e79e96e49cafd33cff2ec748dac79d0bca611cd67aa304e3
3
+ metadata.gz: ed0c19c23a4cbdd7282390be2590b7b9ae8b025badd32ffbaae9adf128d79667
4
+ data.tar.gz: b18729b71798828d9ba517f635e3b2b8e6baff640724b0837bac66be14e72ed8
5
5
  SHA512:
6
- metadata.gz: 1bd5940255d259aeebbe5207a0a397bfade550bbc0e4bf719233ef18c2ba8f3fb483b96fb932fd775f7b98c35af184292b5f7392b32ebf0456888379b13c857c
7
- data.tar.gz: 0ca2437cf6a48c090cc176324477b579c394b11c8c451a14a11c62a9509e5b3f6f722f1318d777e4db610cf4ab004b7f820dba169544fca0c31fb6033d03cf76
6
+ metadata.gz: '0519e4b525fb8e62021c8ec5e518f503c6f14d865f48942c9dd145864f08ca2c3cbfb5c65fae703c3f91c3730ffd04881890d950c335ecc14789cdb28f24a541'
7
+ data.tar.gz: c0068d5051527141d7d1bfd59de4cd5e7b026abbbb5abe2d0a9b45b0a74de674e51bda16d483400f1cdeb9284a7bdb6093ba5989d8eb940e4a431e70bed12ee7
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.10.0] - 2021-12-15
4
+
5
+ - To-do
6
+
7
+ ## [0.9.0] - 2021-12-14
8
+
9
+ - To-do
10
+
11
+ ## [0.8.0] - 2021-12-05
12
+
13
+ - To-do
14
+
15
+ ## [0.7.0] - 2021-12-04
16
+
17
+ - To-do
18
+
3
19
  ## [0.6.0] - 2021-12-03
4
20
 
5
21
  - To-do
data/Gemfile CHANGED
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source "https://rubygems.org"
3
+ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in micro-struct.gemspec
6
6
  gemspec
7
7
 
8
- gem "rake", "~> 13.0"
8
+ gem 'rake', '~> 13.0'
9
9
 
10
- gem "minitest", "~> 5.0"
10
+ gem 'minitest', '~> 5.0'
11
+ gem 'simplecov', '~> 0.21.2'
data/Gemfile.lock CHANGED
@@ -1,21 +1,30 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- u-struct (0.6.0)
4
+ u-struct (0.10.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ docile (1.4.0)
9
10
  minitest (5.14.4)
10
11
  rake (13.0.6)
12
+ simplecov (0.21.2)
13
+ docile (~> 1.1)
14
+ simplecov-html (~> 0.11)
15
+ simplecov_json_formatter (~> 0.1)
16
+ simplecov-html (0.12.3)
17
+ simplecov_json_formatter (0.1.3)
11
18
 
12
19
  PLATFORMS
20
+ ruby
13
21
  x86_64-darwin-19
14
22
 
15
23
  DEPENDENCIES
16
24
  bundler
17
25
  minitest (~> 5.0)
18
26
  rake (~> 13.0)
27
+ simplecov (~> 0.21.2)
19
28
  u-struct!
20
29
 
21
30
  BUNDLED WITH
data/README.md CHANGED
@@ -22,17 +22,24 @@ Or install it yourself as:
22
22
 
23
23
  ```ruby
24
24
  # Like in a regular Struct, you can define one or many attributes.
25
- # But all of will be required by default.
25
+ # But all of them will be required by default.
26
26
 
27
27
  Micro::Struct.new(:first_name, :last_name, ...)
28
28
 
29
- # Use the `_optional:` arg if you want some optional attributes.
29
+ # Use the `optional:` arg if you want some optional attributes.
30
30
 
31
- Micro::Struct.new(:first_name, :last_name, _optional: :gender)
31
+ Micro::Struct.new(:first_name, :last_name, optional: :gender)
32
32
 
33
- # Using `_optional:` to define all attributes are optional.
33
+ # Using `optional:` to define all attributes are optional.
34
34
 
35
- Micro::Struct.new(_optional: [:first_name, :last_name])
35
+ Micro::Struct.new(optional: [:first_name, :last_name])
36
+
37
+ # Use the `required:` arg to define required attributes.
38
+
39
+ Micro::Struct.new(
40
+ required: [:first_name, :last_name],
41
+ optional: [:gender, :age]
42
+ )
36
43
 
37
44
  # You can also pass a block to define custom methods.
38
45
 
@@ -52,11 +59,17 @@ Micro::Struct.with(:to_ary, :to_hash, :to_proc, :readonly, :instance_copy).new(:
52
59
  Micro::Struct.new(*required)
53
60
  Micro::Struct.new(*required) {}
54
61
 
55
- Micro::Struct.new(_optional: *)
56
- Micro::Struct.new(_optional: *) {}
62
+ Micro::Struct.new(optional: *)
63
+ Micro::Struct.new(optional: *) {}
64
+
65
+ Micro::Struct.new(required: *)
66
+ Micro::Struct.new(required: *) {}
67
+
68
+ Micro::Struct.new(*required, optional: *)
69
+ Micro::Struct.new(*required, optional: *) {}
57
70
 
58
- Micro::Struct.new(*required, _optional: *)
59
- Micro::Struct.new(*required, _optional: *) {}
71
+ Micro::Struct.new(required: *, optional: *)
72
+ Micro::Struct.new(required: *, optional: *) {}
60
73
 
61
74
  # Any options above can be used by the `.new()` method of the struct creator returned by the `.with()` method.
62
75
 
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+
8
+ gem 'u-struct', path: '..'
9
+ end
10
+
11
+ Person = Micro::Struct.new(:first_name, :last_name, optional: :age) do
12
+ def name
13
+ "#{first_name} #{last_name}"
14
+ end
15
+ end
16
+
17
+ person = Person.new(first_name: 'Rodrigo', last_name: 'Serradura')
18
+
19
+ puts format('first_name: %p', person.first_name)
20
+ puts format('last_name: %p', person.last_name)
21
+ puts format('name: %p', person.name)
22
+ puts format('age: %p', person.age)
23
+ puts
24
+
25
+ person.age = rand(18..100)
26
+
27
+ puts format('age: %p', person.age)
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+
8
+ gem 'u-struct', path: '..'
9
+ end
10
+
11
+ Person = Micro::Struct.with(:readonly, :instance_copy).new(
12
+ required: [:first_name, :last_name],
13
+ optional: [:age]
14
+ ) do
15
+ def name
16
+ "#{first_name} #{last_name}"
17
+ end
18
+ end
19
+
20
+ person = Person.new(first_name: 'Rodrigo', last_name: 'Serradura')
21
+
22
+ puts format('first_name: %p', person.first_name)
23
+ puts format('last_name: %p', person.last_name)
24
+ puts format('name: %p', person.name)
25
+ puts format('age: %p', person.age)
26
+ puts
27
+
28
+ rand_age = rand(18..100)
29
+
30
+ new_person = person.with(age: rand_age)
31
+
32
+ puts new_person.equal?(person)
33
+
34
+ puts format('age: %p', person.age)
35
+ puts format('age: %p', new_person.age)
36
+
37
+ person.age = rand_age
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RGB
4
+ Color = Micro::Struct.with(:readonly, :to_ary).new(:red, :green, :blue) do
5
+ def self.new(r:, g:, b:)
6
+ __new__(
7
+ red: Number.new(r, label: 'r'),
8
+ green: Number.new(g, label: 'g'),
9
+ blue: Number.new(b, label: 'b')
10
+ )
11
+ end
12
+
13
+ def to_a
14
+ super.map(&:value)
15
+ end
16
+
17
+ def to_hex
18
+ "##{red}#{green}#{blue}"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RGB
4
+ Number = Micro::Struct.with(:readonly).new(:value) do
5
+ Input = Kind.object(name: 'Integer(>= 0 and <= 255)') do |value|
6
+ value.is_a?(::Integer) && value >= 0 && value <= 255
7
+ end
8
+
9
+ def self.new(value, label:)
10
+ __new__(value: Input[value, label: label])
11
+ end
12
+
13
+ def to_s
14
+ value.to_s(16)
15
+ end
16
+ end
17
+ end
data/examples/rgb_1.rb ADDED
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+
8
+ gem 'u-struct', path: '..'
9
+ gem 'kind'
10
+ end
11
+
12
+ RGBColor = Micro::Struct.with(:readonly, :to_ary).new(:red, :green, :blue) do
13
+ Number = Kind.object(name: 'Integer(>= 0 and <= 255)') do |value|
14
+ value.is_a?(::Integer) && value >= 0 && value <= 255
15
+ end
16
+
17
+ def self.new(r:, g:, b:)
18
+ __new__(
19
+ red: Number[r, label: 'r'],
20
+ green: Number[g, label: 'g'],
21
+ blue: Number[b, label: 'b']
22
+ )
23
+ end
24
+
25
+ def to_hex
26
+ "##{red.to_s(16)}#{green.to_s(16)}#{blue.to_s(16)}"
27
+ end
28
+ end
29
+
30
+ rgb_color = RGBColor.new(r: 1, g: 1, b: 255)
31
+
32
+ p rgb_color
33
+
34
+ puts
35
+ puts format('to_hex: %p', rgb_color.to_hex)
36
+ puts format('to_a: %p', rgb_color.to_a)
37
+ puts
38
+
39
+ r, g, b = rgb_color
40
+
41
+ puts format('red: %p', r)
42
+ puts format('green: %p', g)
43
+ puts format('blue: %p', b)
44
+
45
+ RGBColor.new(r: 1, g: -1, b: 255) # Kind::Error (g: -1 expected to be a kind of Integer(>= 0 and <= 255))
data/examples/rgb_2.rb ADDED
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+
8
+ gem 'u-struct', path: '..'
9
+ gem 'kind'
10
+ end
11
+
12
+ RGBNumber = Micro::Struct.with(:readonly).new(:value) do
13
+ Input = Kind.object(name: 'Integer(>= 0 and <= 255)') do |value|
14
+ value.is_a?(::Integer) && value >= 0 && value <= 255
15
+ end
16
+
17
+ def self.new(value, label:)
18
+ __new__(value: Input[value, label: label])
19
+ end
20
+
21
+ def to_s
22
+ value.to_s(16)
23
+ end
24
+ end
25
+
26
+ RGBColor = Micro::Struct.with(:readonly, :to_ary).new(:red, :green, :blue) do
27
+ def self.new(r:, g:, b:)
28
+ __new__(
29
+ red: RGBNumber.new(r, label: 'r'),
30
+ green: RGBNumber.new(g, label: 'g'),
31
+ blue: RGBNumber.new(b, label: 'b')
32
+ )
33
+ end
34
+
35
+ def to_a
36
+ [red.value, green.value, blue.value]
37
+ end
38
+
39
+ def to_hex
40
+ "##{red}#{green}#{blue}"
41
+ end
42
+ end
43
+
44
+ rgb_color = RGBColor.new(r: 1, g: 1, b: 255)
45
+
46
+ p rgb_color
47
+
48
+ puts
49
+ puts format('to_hex: %p', rgb_color.to_hex)
50
+ puts format('to_a: %p', rgb_color.to_a)
51
+ puts
52
+
53
+ r, g, b = rgb_color
54
+
55
+ puts format('red: %p', r)
56
+ puts format('green: %p', g)
57
+ puts format('blue: %p', b)
58
+
59
+ RGB::Color.new(r: 1, g: -1, b: 255) # Kind::Error (g: -1 expected to be a kind of Integer(>= 0 and <= 255))
data/examples/rgb_3.rb ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+
8
+ gem 'u-struct', path: '..'
9
+ gem 'kind'
10
+ end
11
+
12
+ require_relative 'rgb/number'
13
+ require_relative 'rgb/color'
14
+
15
+ rgb_color = RGB::Color.new(r: 1, g: 1, b: 255)
16
+
17
+ p rgb_color
18
+
19
+ puts
20
+ puts format('to_hex: %p', rgb_color.to_hex)
21
+ puts format('to_a: %p', rgb_color.to_a)
22
+ puts
23
+
24
+ r, g, b = rgb_color
25
+
26
+ puts format('red: %p', r)
27
+ puts format('green: %p', g)
28
+ puts format('blue: %p', b)
29
+
30
+ RGB::Color.new(r: 1, g: -1, b: 255) # Kind::Error (g: -1 expected to be a kind of Integer(>= 0 and <= 255))
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Micro::Struct::Factory
4
+ module CreateStruct
5
+ extend self
6
+
7
+ def with(required_members, optional_members, features, &block)
8
+ struct = ::Struct.new(*(required_members + optional_members))
9
+
10
+ def_initialize(struct, required_members, optional_members)
11
+ def_to_ary(struct) if features[:to_ary]
12
+ def_to_hash(struct) if features[:to_hash]
13
+ def_to_proc(struct) if features[:to_proc]
14
+ def_readonly(struct) if features[:readonly]
15
+ def_instance_copy(struct) if features[:instance_copy]
16
+
17
+ struct.class_eval(&block) if block
18
+
19
+ struct
20
+ end
21
+
22
+ private
23
+
24
+ def def_initialize(struct, required_members, optional_members)
25
+ required = "#{required_members.join(':, ')}#{':' unless required_members.empty?}"
26
+ optional = "#{optional_members.join(': nil, ')}#{': nil' unless optional_members.empty?}"
27
+
28
+ keywords_arguments = [required, optional].reject(&:empty?).join(', ')
29
+ positional_arguments = (required_members + optional_members).join(', ')
30
+
31
+ # The .new() method will require all required keyword arguments.
32
+ # We are doing this because the Struct constructor keyword init option treats everything as optional.
33
+ #
34
+ struct.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
35
+ class << self
36
+ undef_method :new
37
+
38
+ def new(#{keywords_arguments}) # def new(a:, b:, c: nil) do
39
+ instance = allocate # instance = allocate
40
+ instance.send(:initialize, #{positional_arguments}) # instance.send(:initialize, a, b, c)
41
+ instance # instance
42
+ end # end
43
+
44
+ alias __new__ new
45
+ end
46
+ RUBY
47
+ end
48
+
49
+ def def_to_ary(struct)
50
+ struct.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
51
+ def to_ary
52
+ to_a
53
+ end
54
+ RUBY
55
+ end
56
+
57
+ def def_to_hash(struct)
58
+ struct.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
59
+ def to_hash
60
+ to_h
61
+ end
62
+ RUBY
63
+ end
64
+
65
+ def def_readonly(struct)
66
+ struct.send(:private, *struct.members.map { |member| "#{member}=" })
67
+ end
68
+
69
+ def def_instance_copy(struct)
70
+ struct.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
71
+ def with(**members)
72
+ self.class.new(**to_h.merge(members))
73
+ end
74
+ RUBY
75
+ end
76
+
77
+ def def_to_proc(struct)
78
+ struct.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
79
+ def self.to_proc
80
+ ->(hash) { new(**hash) }
81
+ end
82
+ RUBY
83
+ end
84
+ end
85
+
86
+ private_constant :CreateStruct
87
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro::Struct
4
+ class Factory
5
+ require_relative 'factory/create_struct'
6
+
7
+ def initialize(features)
8
+ @features = Features.require(features)
9
+ end
10
+
11
+ NormalizeMemberNames = ->(values) do
12
+ NormalizeNames::AsSymbols.(values, context: 'member')
13
+ end
14
+
15
+ def new(*members, required: nil, optional: nil, &block)
16
+ optional_members = NormalizeMemberNames[optional]
17
+ required_members = NormalizeMemberNames[members] + NormalizeMemberNames[required]
18
+
19
+ CreateStruct.with(required_members, optional_members, @features, &block)
20
+ end
21
+ end
22
+
23
+ private_constant :Factory
24
+ end
@@ -7,8 +7,7 @@ module Micro::Struct
7
7
  to_hash: false,
8
8
  to_proc: false,
9
9
  readonly: false,
10
- instance_copy: false
11
- }.freeze
10
+ instance_copy: false }.freeze
12
11
 
13
12
  Check = ->(to_ary:, to_hash:, to_proc:, readonly:, instance_copy:) do
14
13
  { to_ary: to_ary,
@@ -18,15 +17,15 @@ module Micro::Struct
18
17
  instance_copy: instance_copy }
19
18
  end
20
19
 
21
- ValidateFeatureNames = ->(values) do
22
- Validate::Names.(values, label: 'feature')
20
+ NormalizeFeatureNames = ->(values) do
21
+ NormalizeNames::AsSymbols.(values, context: 'feature')
23
22
  end
24
23
 
25
24
  def self.require(names)
26
- features_to_enable =
27
- ValidateFeatureNames[names].each_with_object({}) { |name, memo| memo[name] = true }
25
+ to_enable =
26
+ NormalizeFeatureNames[names].each_with_object({}) { |name, memo| memo[name] = true }
28
27
 
29
- Check.(**DISABLED.merge(features_to_enable))
28
+ Check.(**DISABLED.merge(to_enable))
30
29
  end
31
30
  end
32
31
 
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro::Struct
4
+ module NormalizeNames
5
+ module AsSymbols
6
+ REGEXP = /\A[_A-Za-z]\w*\z/.freeze
7
+ Invalid = ->(context, val) { raise NameError.new("invalid #{context} name: #{val}") }
8
+ AsSymbol = ->(context, val) { REGEXP =~ val ? val.to_sym : Invalid[context, val] }.curry
9
+
10
+ def self.call(values, context:)
11
+ Array(values).map(&AsSymbol[context])
12
+ end
13
+ end
14
+ end
15
+
16
+ private_constant :NormalizeNames
17
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Micro
4
4
  module Struct
5
- VERSION = '0.6.0'
5
+ VERSION = '0.10.0'
6
6
  end
7
7
  end
data/lib/micro/struct.rb CHANGED
@@ -2,22 +2,29 @@
2
2
 
3
3
  require_relative 'struct/version'
4
4
  require_relative 'struct/features'
5
- require_relative 'struct/creator'
6
- require_relative 'struct/validate'
5
+ require_relative 'struct/factory'
6
+ require_relative 'struct/normalize_names'
7
7
 
8
8
  module Micro
9
9
  # Like in a regular Struct, you can define one or many attributes.
10
- # But all of will be required by default.
10
+ # But all of them will be required by default.
11
11
  #
12
12
  # Micro::Struct.new(:first_name, :last_name, ...)
13
13
  #
14
- # Use the `_optional:` arg if you want some optional attributes.
14
+ # Use the `optional:` arg if you want some optional attributes.
15
15
  #
16
- # Micro::Struct.new(:first_name, :last_name, _optional: :gender)
16
+ # Micro::Struct.new(:first_name, :last_name, optional: :gender)
17
17
  #
18
- # Using `_optional:` to define all attributes are optional.
18
+ # Using `optional:` to define all attributes are optional.
19
19
  #
20
- # Micro::Struct.new(_optional: [:first_name, :last_name])
20
+ # Micro::Struct.new(optional: [:first_name, :last_name])
21
+ #
22
+ # Use the `required:` arg to define required attributes.
23
+ #
24
+ # Micro::Struct.new(
25
+ # required: [:first_name, :last_name],
26
+ # optional: [:gender, :age]
27
+ # )
21
28
  #
22
29
  # You can also pass a block to define custom methods.
23
30
  #
@@ -34,25 +41,28 @@ module Micro
34
41
  #
35
42
  # All of the possible combinations to create a Ruby Struct. ;)
36
43
  #
37
- # Micro::Struct.new(*required)
38
- # Micro::Struct.new(*required) {}
44
+ # Micro::Struct.new(optional: *)
45
+ # Micro::Struct.new(optional: *) {}
46
+ #
47
+ # Micro::Struct.new(required: *)
48
+ # Micro::Struct.new(required: *) {}
39
49
  #
40
- # Micro::Struct.new(_optional: *)
41
- # Micro::Struct.new(_optional: *) {}
50
+ # Micro::Struct.new(*required, optional: *)
51
+ # Micro::Struct.new(*required, optional: *) {}
42
52
  #
43
- # Micro::Struct.new(*required, _optional: *)
44
- # Micro::Struct.new(*required, _optional: *) {}
53
+ # Micro::Struct.new(required: *, optional: *)
54
+ # Micro::Struct.new(required: *, optional: *) {}
45
55
  #
46
56
  # Any options above can be used by the `.new()` method of the struct creator returned by the `.with()` method.
47
57
  #
48
58
  # Micro::Struct.with(*features).new(...) {}
49
59
  module Struct
50
- def self.new(*members, _optional: nil, &block)
51
- with.new(*members, _optional: _optional, &block)
60
+ def self.new(*members, required: nil, optional: nil, &block)
61
+ with.new(*members, required: required, optional: optional, &block)
52
62
  end
53
63
 
54
64
  def self.with(*features)
55
- Creator.new(features)
65
+ Factory.new(features)
56
66
  end
57
67
  end
58
68
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: u-struct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-04 00:00:00.000000000 Z
11
+ date: 2021-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -55,12 +55,18 @@ files:
55
55
  - Rakefile
56
56
  - bin/console
57
57
  - bin/setup
58
+ - examples/person_1.rb
59
+ - examples/person_2.rb
60
+ - examples/rgb/color.rb
61
+ - examples/rgb/number.rb
62
+ - examples/rgb_1.rb
63
+ - examples/rgb_2.rb
64
+ - examples/rgb_3.rb
58
65
  - lib/micro/struct.rb
59
- - lib/micro/struct/creator.rb
60
- - lib/micro/struct/creator/create_module.rb
61
- - lib/micro/struct/creator/create_struct.rb
66
+ - lib/micro/struct/factory.rb
67
+ - lib/micro/struct/factory/create_struct.rb
62
68
  - lib/micro/struct/features.rb
63
- - lib/micro/struct/validate.rb
69
+ - lib/micro/struct/normalize_names.rb
64
70
  - lib/micro/struct/version.rb
65
71
  - lib/u-struct.rb
66
72
  - u-struct.gemspec
@@ -86,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
92
  - !ruby/object:Gem::Version
87
93
  version: '0'
88
94
  requirements: []
89
- rubygems_version: 3.2.21
95
+ rubygems_version: 3.2.17
90
96
  signing_key:
91
97
  specification_version: 4
92
98
  summary: Create powered Ruby structs.
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Micro::Struct::Creator
4
- module CreateModule
5
- extend self
6
-
7
- def with(required_members, optional_members, features)
8
- container = Module.new
9
-
10
- def_initialize_and_members(container, required_members, optional_members)
11
-
12
- def_to_proc(container) if features[:to_proc]
13
-
14
- container
15
- end
16
-
17
- private
18
-
19
- def def_initialize_and_members(container, required_members, optional_members)
20
- required = "#{required_members.join(':, ')}#{':' unless required_members.empty?}"
21
- optional = "#{optional_members.join(': nil, ')}#{': nil' unless optional_members.empty?}"
22
-
23
- method_arguments = [required, optional].reject(&:empty?).join(', ')
24
- struct_arguments = (required_members + optional_members).join(', ')
25
-
26
- container.module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
27
- # The .new() method will require all required keyword arguments.
28
- # We are doing this because the Struct constructor keyword init option treats everything as optional.
29
- #
30
- def self.new(#{method_arguments}) # def self.new(a:, b:) do
31
- Struct.send(:new, #{struct_arguments}) # Struct.send(:new, a, b)
32
- end # end
33
-
34
- def self.members
35
- Struct.members
36
- end
37
- RUBY
38
- end
39
-
40
- def def_to_proc(container)
41
- container.module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
42
- def self.to_proc
43
- ->(hash) { new(**hash) }
44
- end
45
- RUBY
46
- end
47
- end
48
-
49
- private_constant :CreateModule
50
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class Micro::Struct::Creator
4
- module CreateStruct
5
- extend self
6
-
7
- def with(required_members, optional_members, features, &block)
8
- struct = ::Struct.new(*(required_members + optional_members), &block)
9
- struct.send(:private_class_method, :new)
10
-
11
- def_to_ary(struct) if features[:to_ary]
12
- def_to_hash(struct) if features[:to_hash]
13
- def_readonly(struct) if features[:readonly]
14
- def_instance_copy(struct) if features[:readonly] || features[:instance_copy]
15
-
16
- struct
17
- end
18
-
19
- private
20
-
21
- def def_to_ary(struct)
22
- struct.send(:alias_method, :to_ary, :to_a)
23
- end
24
-
25
- def def_to_hash(struct)
26
- struct.send(:alias_method, :to_hash, :to_h)
27
- end
28
-
29
- def def_readonly(struct)
30
- struct.send(:private, *struct.members.map { |member| "#{member}=" })
31
- end
32
-
33
- def def_instance_copy(struct)
34
- struct.class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
35
- def with(**members)
36
- self.class.const_get(:Container, false).new(**to_h.merge(members))
37
- end
38
- RUBY
39
- end
40
- end
41
-
42
- private_constant :CreateStruct
43
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Micro::Struct
4
- class Creator
5
- require_relative 'creator/create_module'
6
- require_relative 'creator/create_struct'
7
-
8
- def initialize(features)
9
- @features = Features.require(features)
10
- end
11
-
12
- ValidateMemberNames = ->(values) do
13
- Validate::Names.(values, label: 'member')
14
- end
15
-
16
- def new(*members, _optional: nil, &block)
17
- required_members = ValidateMemberNames[members]
18
- optional_members = ValidateMemberNames[_optional]
19
-
20
- container = CreateModule.with(required_members, optional_members, @features)
21
- struct = CreateStruct.with(required_members, optional_members, @features, &block)
22
-
23
- container.const_set(:Struct, struct)
24
- struct.const_set(:Container, container)
25
- end
26
- end
27
-
28
- private_constant :Creator
29
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Micro::Struct
4
- module Validate
5
- module Names
6
- REGEXP = /\A[_A-Za-z]\w*\z/.freeze
7
- Invalid = ->(label, val) { raise NameError.new("invalid #{label} name: #{val}") }
8
- AsSymbol = ->(label, val) { REGEXP =~ val ? val.to_sym : Invalid[label, val] }.curry
9
-
10
- def self.call(values, label:)
11
- Array(values).map(&Names::AsSymbol[label])
12
- end
13
- end
14
- end
15
-
16
- private_constant :Validate
17
- end