u-struct 0.6.0 → 0.10.0

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