u-struct 0.3.1 → 0.7.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: 39ecf73c68816127a9919b2ba6fcfc99c4dec9d10e37a15bbcc8ebee881b468c
4
- data.tar.gz: afe359b57dd0561e93309107c1c2bbad3521a70b9fada6dddef02b3d28820bb6
3
+ metadata.gz: f4b40b69da026b0f45f5514a8d340effc8f7d81489c4f1217237c16641186357
4
+ data.tar.gz: 6a5cd7b12d2d1b16830a805b9904e5c212c685d5a32108439e8f9f2b8235dfb8
5
5
  SHA512:
6
- metadata.gz: cb2708d1a4eabab4da1e1832153babae1f756fbd869e9053de7d62a2f829bfe30ec0c50df66f1cf9139e58d1e65f749d1a12b01b19addf904748fe1f6d7997e3
7
- data.tar.gz: ad4276c480a8e2225c81ea1a9b02fa53fd9bce94d9a3279d94a7d20dc329cc87921c8869a5fd727dc28db2a0e9489273b6a9f37ebf8b304222a67d366a347fea
6
+ metadata.gz: 159075d6944696849893dd4f4860613b104b12f3e872c0cac65df62055af61309d9f9256a949693a01df7fb5b514e916755bf0f6f1295874d93b9bc1abb2a2b3
7
+ data.tar.gz: 12db20998fcd5b1688e4786766630cee699daffacfca72d18e3e769ac387931dd310a46ff511862c7d9d9f2a458ae8667dd3e7623dbfca55802caa41fd3cfbb8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.7.0] - 2021-12-04
4
+
5
+ - To-do
6
+
7
+ ## [0.6.0] - 2021-12-03
8
+
9
+ - To-do
10
+
11
+ ## [0.5.0] - 2021-12-03
12
+
13
+ - To-do
14
+
15
+ ## [0.4.0] - 2021-12-03
16
+
17
+ - To-do
18
+
19
+ ## [0.3.1] - 2021-12-02
20
+
21
+ - To-do
22
+
23
+ ## [0.3.0] - 2021-12-02
24
+
25
+ - To-do
26
+
27
+ ## [0.2.0] - 2021-12-02
28
+
29
+ - To-do
30
+
3
31
  ## [0.1.0] - 2021-12-02
4
32
 
5
33
  - Initial release
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,13 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- u-struct (0.3.1)
4
+ u-struct (0.7.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
13
20
  x86_64-darwin-19
@@ -16,7 +23,8 @@ DEPENDENCIES
16
23
  bundler
17
24
  minitest (~> 5.0)
18
25
  rake (~> 13.0)
26
+ simplecov (~> 0.21.2)
19
27
  u-struct!
20
28
 
21
29
  BUNDLED WITH
22
- 2.2.26
30
+ 2.2.32
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # Micro::Struct
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/micro/struct`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ Create powered Ruby structs.
6
4
 
7
5
  ## Installation
8
6
 
@@ -22,7 +20,61 @@ Or install it yourself as:
22
20
 
23
21
  ## Usage
24
22
 
25
- TODO: Write usage instructions here
23
+ ```ruby
24
+ # Like in a regular Struct, you can define one or many attributes.
25
+ # But all of will be required by default.
26
+
27
+ Micro::Struct.new(:first_name, :last_name, ...)
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
+
44
+ # You can also pass a block to define custom methods.
45
+
46
+ Micro::Struct.new(:name) {}
47
+
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)
50
+
51
+ Micro::Struct.with(:to_ary).new(:name)
52
+ Micro::Struct.with(:to_ary, :to_hash).new(:name)
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.
75
+
76
+ Micro::Struct.with(*features).new(...) {}
77
+ ```
26
78
 
27
79
  ## Development
28
80
 
@@ -0,0 +1,50 @@
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
@@ -0,0 +1,43 @@
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
@@ -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,34 @@
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
11
+ }.freeze
12
+
13
+ Check = ->(to_ary:, to_hash:, to_proc:, readonly:, instance_copy:) do
14
+ { to_ary: to_ary,
15
+ to_hash: to_hash,
16
+ to_proc: to_proc,
17
+ readonly: readonly,
18
+ instance_copy: instance_copy }
19
+ end
20
+
21
+ NormalizeFeatureNames = ->(values) do
22
+ NormalizeNames::AsSymbols.(values, context: 'feature')
23
+ end
24
+
25
+ def self.require(names)
26
+ to_enable =
27
+ NormalizeFeatureNames[names].each_with_object({}) { |name, memo| memo[name] = true }
28
+
29
+ Check.(**DISABLED.merge(to_enable))
30
+ end
31
+ end
32
+
33
+ private_constant :Features
34
+ 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.3.1'
5
+ VERSION = '0.7.0'
6
6
  end
7
7
  end
data/lib/micro/struct.rb CHANGED
@@ -1,32 +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
9
+ # Like in a regular Struct, you can define one or many attributes.
10
+ # But all of will be required by default.
11
+ #
12
+ # Micro::Struct.new(:first_name, :last_name, ...)
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
+ #
29
+ # You can also pass a block to define custom methods.
30
+ #
31
+ # Micro::Struct.new(:name) {}
32
+ #
33
+ # Available features (use one, many, or all) to create Structs with a special behavior:
34
+ # .with(:to_ary, :to_hash, :to_proc, :readonly, :instance_copy)
35
+ #
36
+ # Micro::Struct.with(:to_ary).new(:name)
37
+ # Micro::Struct.with(:to_ary, :to_hash).new(:name)
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: *) {}
46
+ #
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(...) {}
6
59
  module Struct
7
- def self.new(*keys, &block)
8
- struct = ::Struct.new(*keys, &block)
9
-
10
- struct.send(:private_class_method, :new)
11
- struct.send(:alias_method, :to_ary, :to_a)
12
- struct.send(:alias_method, :to_hash, :to_h)
13
-
14
- mod = Module.new
15
- mod.const_set(:Struct, struct)
16
-
17
- # The .new() method will require all of the Struct's keyword arguments.
18
- # We are doing this because Struct's keyword_init option doesn't do that.
19
- mod.module_eval(<<~RUBY, __FILE__, __LINE__ + 1) #
20
- def self.new(#{struct.members.join(':, ')}:) # def self.new(a:, b:) do
21
- Struct.send(:new, #{struct.members.join(', ')}) # Struct.send(:new, a, b)
22
- end # end
23
-
24
- def self.to_proc
25
- ->(hash) { new(**hash) }
26
- end
27
- RUBY
60
+ def self.new(*members, required: nil, optional: nil, &block)
61
+ with.new(*members, required: required, optional: optional, &block)
62
+ end
28
63
 
29
- mod
64
+ def self.with(*features)
65
+ Creator.new(features)
30
66
  end
31
67
  end
32
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.3.1
4
+ version: 0.7.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-02 00:00:00.000000000 Z
11
+ date: 2021-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -56,6 +56,11 @@ files:
56
56
  - bin/console
57
57
  - bin/setup
58
58
  - 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
62
+ - lib/micro/struct/features.rb
63
+ - lib/micro/struct/normalize_names.rb
59
64
  - lib/micro/struct/version.rb
60
65
  - lib/u-struct.rb
61
66
  - u-struct.gemspec
@@ -81,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
86
  - !ruby/object:Gem::Version
82
87
  version: '0'
83
88
  requirements: []
84
- rubygems_version: 3.2.17
89
+ rubygems_version: 3.2.21
85
90
  signing_key:
86
91
  specification_version: 4
87
92
  summary: Create powered Ruby structs.