u-struct 0.5.0 → 0.9.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: 393ba5215b21bf91ef0229de920ca0980c44168fcc0e65d539a0f6b4f6a7caa2
4
- data.tar.gz: e1ad5cfbd6215982aa8f6e5708d4a6f8cea0a046da9ad82568d0ed8136d58629
3
+ metadata.gz: '0765309623bfa9eb720102c66cd30f5ba785bdada60af711f19a03a51a7027bd'
4
+ data.tar.gz: 216dd4920427d682c9e797e5ec0a8631486b5d8c0613391440bd0f94f2778824
5
5
  SHA512:
6
- metadata.gz: 2d86bb3a75737927e5f74d56e16c7760b8c7b9c3dce7642ebdef058122212dd21c38aec04573722842ea081995b5e03c6a094a1548bf63f1ed709762c6e5ad2c
7
- data.tar.gz: 6dee9c1ab9cd6ba5675cf7c1e6cedc128e70fe45aabf52a2b1beb77fb63e9b01c1d70b0775b4393167132371923b5d56a2efed099048e0e3e594b5c199d95ab3
6
+ metadata.gz: ed911103da03769ac8014a618d713b313e20a19a65074ac1a737f2d4cd1717dbdf521d0f7693665d840bdbff145e518afe3e7ef875b1eef55d2555e198bf8d62
7
+ data.tar.gz: 683f94804b10f3ff03ed3f6ecbf4ff40c889dacf8dfd964496e8807974f96cbb611399fa21d95d73881a9c20d4dd0296975528cafc59dfbb20128471149c398a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.9.0] - 2021-12-14
4
+
5
+ - To-do
6
+
7
+ ## [0.8.0] - 2021-12-05
8
+
9
+ - To-do
10
+
11
+ ## [0.7.0] - 2021-12-04
12
+
13
+ - To-do
14
+
15
+ ## [0.6.0] - 2021-12-03
16
+
17
+ - To-do
18
+
3
19
  ## [0.5.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.5.0)
4
+ u-struct (0.9.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,19 +22,58 @@ 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 them will be required by default.
26
+
25
27
  Micro::Struct.new(:first_name, :last_name, ...)
26
28
 
29
+ # Use the `optional:` arg if you want some optional attributes.
30
+
31
+ Micro::Struct.new(:first_name, :last_name, optional: :gender)
32
+
33
+ # Using `optional:` to define all attributes are optional.
34
+
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
+ )
43
+
27
44
  # You can also pass a block to define custom methods.
45
+
28
46
  Micro::Struct.new(:name) {}
29
47
 
30
- # Available features (use one, many or all):
31
- # .with(:to_ary, :to_hash, :to_proc, :readonly, :instance_copy)
48
+ # Available features (use one, many, or all) to create Structs with a special behavior:
49
+ # .with(:to_ary, :to_hash, :to_proc, :readonly, :instance_copy)
32
50
 
33
51
  Micro::Struct.with(:to_ary).new(:name)
34
52
  Micro::Struct.with(:to_ary, :to_hash).new(:name)
35
53
  Micro::Struct.with(:to_ary, :to_hash, :to_proc).new(:name)
54
+ Micro::Struct.with(:to_ary, :to_hash, :to_proc, :readonly).new(:name)
55
+ Micro::Struct.with(:to_ary, :to_hash, :to_proc, :readonly, :instance_copy).new(:name)
56
+
57
+ # All of the possible combinations to create a Ruby Struct. ;)
58
+
59
+ Micro::Struct.new(*required)
60
+ Micro::Struct.new(*required) {}
61
+
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: *) {}
70
+
71
+ Micro::Struct.new(required: *, optional: *)
72
+ Micro::Struct.new(required: *, optional: *) {}
73
+
74
+ # Any options above can be used by the `.new()` method of the struct creator returned by the `.with()` method.
36
75
 
37
- Micro::Struct.with(...).new(...) {}
76
+ Micro::Struct.with(*features).new(...) {}
38
77
  ```
39
78
 
40
79
  ## Development
@@ -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,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RGB
4
+ Color = Micro::Struct.with(:readonly, :to_ary).new(:red, :green, :blue) do
5
+ def to_a
6
+ super.map(&:value)
7
+ end
8
+
9
+ def to_hex
10
+ "##{red}#{green}#{blue}"
11
+ end
12
+ end
13
+
14
+ module Color
15
+ def self.new(r:, g:, b:)
16
+ __new__(
17
+ red: Number.new(r, label: 'r'),
18
+ green: Number.new(g, label: 'g'),
19
+ blue: Number.new(b, label: 'b')
20
+ )
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RGB
4
+ Number = Micro::Struct.with(:readonly).new(:value) do
5
+ def to_s
6
+ value.to_s(16)
7
+ end
8
+ end
9
+
10
+ module Number
11
+ Input = Kind.object(name: 'Integer(>= 0 and <= 255)') do |value|
12
+ value.is_a?(::Integer) && value >= 0 && value <= 255
13
+ end
14
+
15
+ def self.new(value, label:)
16
+ __new__(value: Input[value, label: label])
17
+ end
18
+ end
19
+ end
data/examples/rgb_1.rb ADDED
@@ -0,0 +1,47 @@
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
+ def to_hex
14
+ "##{red.to_s(16)}#{green.to_s(16)}#{blue.to_s(16)}"
15
+ end
16
+ end
17
+
18
+ module RGBColor
19
+ ColorNumber = Kind.object(name: 'Integer(>= 0 and <= 255)') do |value|
20
+ value.is_a?(::Integer) && value >= 0 && value <= 255
21
+ end
22
+
23
+ def self.new(r:, g:, b:)
24
+ __new__(
25
+ red: ColorNumber[r, label: 'r'],
26
+ green: ColorNumber[g, label: 'g'],
27
+ blue: ColorNumber[b, label: 'b']
28
+ )
29
+ end
30
+ end
31
+
32
+ rgb_color = RGBColor.new(r: 1, g: 1, b: 255)
33
+
34
+ p rgb_color
35
+
36
+ puts
37
+ puts format('to_hex: %p', rgb_color.to_hex)
38
+ puts format('to_a: %p', rgb_color.to_a)
39
+ puts
40
+
41
+ r, g, b = rgb_color
42
+
43
+ puts format('red: %p', r)
44
+ puts format('green: %p', g)
45
+ puts format('blue: %p', b)
46
+
47
+ 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,63 @@
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
+ def to_s
14
+ value.to_s(16)
15
+ end
16
+ end
17
+
18
+ module RGBNumber
19
+ Input = Kind.object(name: 'Integer(>= 0 and <= 255)') do |value|
20
+ value.is_a?(::Integer) && value >= 0 && value <= 255
21
+ end
22
+
23
+ def self.new(value, label:)
24
+ __new__(value: Input[value, label: label])
25
+ end
26
+ end
27
+
28
+ RGBColor = Micro::Struct.with(:readonly, :to_ary).new(:red, :green, :blue) do
29
+ def to_a
30
+ [red.value, green.value, blue.value]
31
+ end
32
+
33
+ def to_hex
34
+ "##{red}#{green}#{blue}"
35
+ end
36
+ end
37
+
38
+ module RGBColor
39
+ def self.new(r:, g:, b:)
40
+ __new__(
41
+ red: RGBNumber.new(r, label: 'r'),
42
+ green: RGBNumber.new(g, label: 'g'),
43
+ blue: RGBNumber.new(b, label: 'b')
44
+ )
45
+ end
46
+ end
47
+
48
+ rgb_color = RGBColor.new(r: 1, g: 1, b: 255)
49
+
50
+ p rgb_color
51
+
52
+ puts
53
+ puts format('to_hex: %p', rgb_color.to_hex)
54
+ puts format('to_a: %p', rgb_color.to_a)
55
+ puts
56
+
57
+ r, g, b = rgb_color
58
+
59
+ puts format('red: %p', r)
60
+ puts format('green: %p', g)
61
+ puts format('blue: %p', b)
62
+
63
+ 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,67 @@
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(container, required_members, optional_members)
11
+ def_triple_eq(container)
12
+ def_members(container)
13
+ def_to_proc(container) if features[:to_proc]
14
+
15
+ container
16
+ end
17
+
18
+ private
19
+
20
+ def def_initialize(container, required_members, optional_members)
21
+ required = "#{required_members.join(':, ')}#{':' unless required_members.empty?}"
22
+ optional = "#{optional_members.join(': nil, ')}#{': nil' unless optional_members.empty?}"
23
+
24
+ method_arguments = [required, optional].reject(&:empty?).join(', ')
25
+ struct_arguments = (required_members + optional_members).join(', ')
26
+
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
+ container.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
31
+ def self.__new__(#{method_arguments}) # def self.__new__(a:, b:) do
32
+ Struct.send(:new, #{struct_arguments}) # Struct.send(:new, a, b)
33
+ end # end
34
+
35
+ class << self
36
+ alias new __new__
37
+ end
38
+ RUBY
39
+ end
40
+
41
+ def def_triple_eq(container)
42
+ container.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
43
+ def self.===(other)
44
+ Struct === other
45
+ end
46
+ RUBY
47
+ end
48
+
49
+ def def_members(container)
50
+ container.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
51
+ def self.members
52
+ Struct.members
53
+ end
54
+ RUBY
55
+ end
56
+
57
+ def def_to_proc(container)
58
+ container.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
59
+ def self.to_proc
60
+ ->(hash) { new(**hash) }
61
+ end
62
+ RUBY
63
+ end
64
+ end
65
+
66
+ private_constant :CreateModule
67
+ end
@@ -0,0 +1,51 @@
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[:instance_copy]
15
+
16
+ struct
17
+ end
18
+
19
+ private
20
+
21
+ def def_to_ary(struct)
22
+ struct.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
23
+ def to_ary
24
+ to_a
25
+ end
26
+ RUBY
27
+ end
28
+
29
+ def def_to_hash(struct)
30
+ struct.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
31
+ def to_hash
32
+ to_h
33
+ end
34
+ RUBY
35
+ end
36
+
37
+ def def_readonly(struct)
38
+ struct.send(:private, *struct.members.map { |member| "#{member}=" })
39
+ end
40
+
41
+ def def_instance_copy(struct)
42
+ struct.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
43
+ def with(**members)
44
+ self.class.const_get(:Container, false).new(**to_h.merge(members))
45
+ end
46
+ RUBY
47
+ end
48
+ end
49
+
50
+ private_constant :CreateStruct
51
+ end
@@ -0,0 +1,29 @@
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
+ NormalizeMemberNames = ->(values) do
13
+ NormalizeNames::AsSymbols.(values, context: 'member')
14
+ end
15
+
16
+ def new(*members, required: nil, optional: nil, &block)
17
+ optional_members = NormalizeMemberNames[optional]
18
+ required_members = NormalizeMemberNames[members] + NormalizeMemberNames[required]
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
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro::Struct
4
+ module Features
5
+ DISABLED =
6
+ { to_ary: false,
7
+ to_hash: false,
8
+ to_proc: false,
9
+ readonly: false,
10
+ instance_copy: false }.freeze
11
+
12
+ Check = ->(to_ary:, to_hash:, to_proc:, readonly:, instance_copy:) do
13
+ { to_ary: to_ary,
14
+ to_hash: to_hash,
15
+ to_proc: to_proc,
16
+ readonly: readonly,
17
+ instance_copy: instance_copy }
18
+ end
19
+
20
+ NormalizeFeatureNames = ->(values) do
21
+ NormalizeNames::AsSymbols.(values, context: 'feature')
22
+ end
23
+
24
+ def self.require(names)
25
+ to_enable =
26
+ NormalizeFeatureNames[names].each_with_object({}) { |name, memo| memo[name] = true }
27
+
28
+ Check.(**DISABLED.merge(to_enable))
29
+ end
30
+ end
31
+
32
+ private_constant :Features
33
+ end
@@ -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.5.0'
5
+ VERSION = '0.9.0'
6
6
  end
7
7
  end
data/lib/micro/struct.rb CHANGED
@@ -1,141 +1,68 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'struct/version'
4
+ require_relative 'struct/features'
5
+ require_relative 'struct/creator'
6
+ require_relative 'struct/normalize_names'
4
7
 
5
8
  module Micro
6
9
  # Like in a regular Struct, you can define one or many attributes.
10
+ # But all of them will be required by default.
11
+ #
7
12
  # Micro::Struct.new(:first_name, :last_name, ...)
8
13
  #
14
+ # Use the `optional:` arg if you want some optional attributes.
15
+ #
16
+ # Micro::Struct.new(:first_name, :last_name, optional: :gender)
17
+ #
18
+ # Using `optional:` to define all attributes are optional.
19
+ #
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
+ # )
28
+ #
9
29
  # You can also pass a block to define custom methods.
30
+ #
10
31
  # Micro::Struct.new(:name) {}
11
32
  #
12
- # Available features (use one, many or all):
33
+ # Available features (use one, many, or all) to create Structs with a special behavior:
13
34
  # .with(:to_ary, :to_hash, :to_proc, :readonly, :instance_copy)
14
35
  #
15
36
  # Micro::Struct.with(:to_ary).new(:name)
16
37
  # Micro::Struct.with(:to_ary, :to_hash).new(:name)
17
38
  # Micro::Struct.with(:to_ary, :to_hash, :to_proc).new(:name)
39
+ # Micro::Struct.with(:to_ary, :to_hash, :to_proc, :readonly).new(:name)
40
+ # Micro::Struct.with(:to_ary, :to_hash, :to_proc, :readonly, :instance_copy).new(:name)
41
+ #
42
+ # All of the possible combinations to create a Ruby Struct. ;)
43
+ #
44
+ # Micro::Struct.new(optional: *)
45
+ # Micro::Struct.new(optional: *) {}
18
46
  #
19
- # Micro::Struct.with(...).new(...) {}
47
+ # Micro::Struct.new(required: *)
48
+ # Micro::Struct.new(required: *) {}
49
+ #
50
+ # Micro::Struct.new(*required, optional: *)
51
+ # Micro::Struct.new(*required, optional: *) {}
52
+ #
53
+ # Micro::Struct.new(required: *, optional: *)
54
+ # Micro::Struct.new(required: *, optional: *) {}
55
+ #
56
+ # Any options above can be used by the `.new()` method of the struct creator returned by the `.with()` method.
57
+ #
58
+ # Micro::Struct.with(*features).new(...) {}
20
59
  module Struct
21
- class Creator
22
- module Features
23
- DISABLED =
24
- { to_ary: false,
25
- to_hash: false,
26
- to_proc: false,
27
- readonly: false,
28
- instance_copy: false
29
- }.freeze
30
-
31
- Expose = ->(to_ary:, to_hash:, to_proc:, readonly:, instance_copy:) do
32
- { to_ary: to_ary,
33
- to_hash: to_hash,
34
- to_proc: to_proc,
35
- readonly: readonly,
36
- instance_copy: instance_copy }
37
- end
38
-
39
- def self.check(names)
40
- features_to_enable =
41
- Array(names).each_with_object({}) { |name, memo| memo[name] = true }
42
-
43
- Expose.(**DISABLED.merge(features_to_enable))
44
- end
45
- end
46
-
47
- def initialize(features)
48
- @features = Features.check(features)
49
- end
50
-
51
- def new(*members, &block)
52
- def_container do |container|
53
- def_struct(container, members, block) do |struct|
54
- def_initialize(container, struct)
55
-
56
- def_to_ary(struct)
57
- def_to_hash(struct)
58
- def_readonly(struct)
59
- def_instance_copy(struct)
60
- end
61
-
62
- def_to_proc(container)
63
- end
64
- end
65
-
66
- private
67
-
68
- def def_container(&block)
69
- Module.new.tap(&block)
70
- end
71
-
72
- def def_struct(container, members, block)
73
- struct = ::Struct.new(*members, &block)
74
- struct.const_set(:Container, container)
75
- struct.send(:private_class_method, :new)
76
-
77
- container.const_set(:Struct, struct)
78
-
79
- yield struct
80
- end
81
-
82
- def def_initialize(container, struct)
83
- # The .new() method will require all of the Struct's keyword arguments.
84
- # We are doing this because Struct's keyword_init option doesn't do that.
85
- container.module_eval(<<~RUBY, __FILE__, __LINE__ + 1) #
86
- def self.new(#{struct.members.join(':, ')}:) # def self.new(a:, b:) do
87
- Struct.send(:new, #{struct.members.join(', ')}) # Struct.send(:new, a, b)
88
- end # end
89
-
90
- def self.members
91
- Struct.members
92
- end
93
- RUBY
94
- end
95
-
96
- def def_to_ary(struct)
97
- struct.send(:alias_method, :to_ary, :to_a) if @features[:to_ary]
98
- end
99
-
100
- def def_to_hash(struct)
101
- struct.send(:alias_method, :to_hash, :to_h) if @features[:to_hash]
102
- end
103
-
104
- def def_readonly(struct)
105
- return unless @features[:readonly]
106
-
107
- struct.send(:private, *struct.members.map { |member| "#{member}=" })
108
- end
109
-
110
- def def_instance_copy(struct)
111
- return unless (@features[:readonly] || @features[:instance_copy])
112
-
113
- struct.class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
114
- def with(**members)
115
- self.class.const_get(:Container, false).new(**to_h.merge(members))
116
- end
117
- RUBY
118
- end
119
-
120
- def def_to_proc(container)
121
- return unless @features[:to_proc]
122
-
123
- container.module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
124
- def self.to_proc
125
- ->(hash) { new(**hash) }
126
- end
127
- RUBY
128
- end
129
- end
130
-
131
- def self.new(*members, &block)
132
- with.new(*members, &block)
60
+ def self.new(*members, required: nil, optional: nil, &block)
61
+ with.new(*members, required: required, optional: optional, &block)
133
62
  end
134
63
 
135
64
  def self.with(*features)
136
65
  Creator.new(features)
137
66
  end
138
-
139
- private_constant :Creator
140
67
  end
141
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.5.0
4
+ version: 0.9.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-03 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,7 +55,19 @@ 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
66
+ - lib/micro/struct/creator.rb
67
+ - lib/micro/struct/creator/create_module.rb
68
+ - lib/micro/struct/creator/create_struct.rb
69
+ - lib/micro/struct/features.rb
70
+ - lib/micro/struct/normalize_names.rb
59
71
  - lib/micro/struct/version.rb
60
72
  - lib/u-struct.rb
61
73
  - u-struct.gemspec
@@ -81,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
93
  - !ruby/object:Gem::Version
82
94
  version: '0'
83
95
  requirements: []
84
- rubygems_version: 3.2.21
96
+ rubygems_version: 3.2.17
85
97
  signing_key:
86
98
  specification_version: 4
87
99
  summary: Create powered Ruby structs.