u-struct 0.7.0 → 0.11.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 +4 -4
- data/.github/workflows/ci.yml +27 -0
- data/.gitignore +2 -0
- data/.vscode/settings.json +8 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +1 -1
- data/README.md +22 -4
- data/bin/prepare_coverage +27 -0
- data/bin/test +8 -0
- data/examples/person_1.rb +27 -0
- data/examples/person_2.rb +37 -0
- data/examples/rgb/color.rb +21 -0
- data/examples/rgb/number.rb +21 -0
- data/examples/rgb_1.rb +53 -0
- data/examples/rgb_2.rb +75 -0
- data/examples/rgb_3.rb +42 -0
- data/lib/micro/struct/factory/create_struct.rb +88 -0
- data/lib/micro/struct/factory/members.rb +37 -0
- data/lib/micro/struct/factory.rb +20 -0
- data/lib/micro/struct/features.rb +4 -6
- data/lib/micro/struct/version.rb +1 -1
- data/lib/micro/struct.rb +3 -3
- data/u-struct.gemspec +1 -1
- metadata +18 -8
- data/Gemfile.lock +0 -30
- data/lib/micro/struct/creator/create_module.rb +0 -50
- data/lib/micro/struct/creator/create_struct.rb +0 -43
- data/lib/micro/struct/creator.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0150b18cb61a38d042a0ad2f22c9588c7269c8362a708a8ebf156cc927a312dd
|
4
|
+
data.tar.gz: 0fc97adb461433c7382ee524d3a58c4d134624013c4afa974cade30b46f09109
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 708cbec302ef69ec3d6f465ebca2d07eff62ff1a3746b4e7034b21a571e693b27b9e4dad1ada934f4ac37f2565212cc83f111d384eb84573209578aab77beac6
|
7
|
+
data.tar.gz: cec5b4750bcc98d9955fbe27bcca952b2139c36dd90d6f6c98fd3b107f9ef577fdb2e72f34c78871e15d608cdab06c034427efeab67caa5bc2c869bbaeee8026
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
name: build
|
3
|
+
on: [push]
|
4
|
+
jobs:
|
5
|
+
test:
|
6
|
+
runs-on: ubuntu-latest
|
7
|
+
strategy:
|
8
|
+
matrix:
|
9
|
+
ruby: [2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1.0-preview1]
|
10
|
+
steps:
|
11
|
+
- uses: actions/checkout@v2
|
12
|
+
- uses: ruby/setup-ruby@v1
|
13
|
+
with:
|
14
|
+
ruby-version: ${{ matrix.ruby }}
|
15
|
+
bundler-cache: true
|
16
|
+
- name: Test and generate coverage
|
17
|
+
run: bin/test
|
18
|
+
- name: Format coverage
|
19
|
+
if: ${{ matrix.ruby >= 3 && matrix.ruby < 3.1 }}
|
20
|
+
run: bin/prepare_coverage
|
21
|
+
- uses: paambaati/codeclimate-action@v2.7.5
|
22
|
+
if: ${{ matrix.ruby >= 3 && matrix.ruby < 3.1 }}
|
23
|
+
env:
|
24
|
+
CC_TEST_REPORTER_ID: 8ce350edeb0772e94ffd678bbaca30d9c1293b9d9051a1689c79b91c21f5afd5
|
25
|
+
with:
|
26
|
+
debug: true
|
27
|
+
coverageLocations: coverage/.resultset.json:simplecov
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,24 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
Create powered Ruby structs
|
1
|
+
<p align="center">
|
2
|
+
<h1 align="center">🧱 μ-struct</h1>
|
3
|
+
<p align="center"><i>Create powered Ruby structs.</i></p>
|
4
|
+
<br>
|
5
|
+
</p>
|
6
|
+
|
7
|
+
<p align="center">
|
8
|
+
<img src="https://img.shields.io/badge/ruby%20%3E=%202.2,%20%3C%203.2-ruby.svg?colorA=99004d&colorB=cc0066" alt="Ruby">
|
9
|
+
<a href="https://rubygems.org/gems/u-struct">
|
10
|
+
<img alt="Gem" src="https://img.shields.io/gem/v/u-struct.svg?style=flat-square">
|
11
|
+
</a>
|
12
|
+
<a href="https://github.com/serradura/u-struct/actions/workflows/ci.yml">
|
13
|
+
<img alt="Build Status" src="https://github.com/serradura/u-struct/actions/workflows/ci.yml/badge.svg">
|
14
|
+
</a>
|
15
|
+
<a href="https://codeclimate.com/github/serradura/u-struct/maintainability">
|
16
|
+
<img alt="Maintainability" src="https://api.codeclimate.com/v1/badges/2cc0204411cc2b392b7a/maintainability">
|
17
|
+
</a>
|
18
|
+
<a href="https://codeclimate.com/github/serradura/u-struct/test_coverage">
|
19
|
+
<img alt="Test Coverage" src="https://api.codeclimate.com/v1/badges/2cc0204411cc2b392b7a/test_coverage">
|
20
|
+
</a>
|
21
|
+
</p>
|
4
22
|
|
5
23
|
## Installation
|
6
24
|
|
@@ -22,7 +40,7 @@ Or install it yourself as:
|
|
22
40
|
|
23
41
|
```ruby
|
24
42
|
# Like in a regular Struct, you can define one or many attributes.
|
25
|
-
# But all of will be required by default.
|
43
|
+
# But all of them will be required by default.
|
26
44
|
|
27
45
|
Micro::Struct.new(:first_name, :last_name, ...)
|
28
46
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
# Borrowed from https://gist.github.com/qortex/7e7c49f3731391a91ee898336183acef
|
4
|
+
|
5
|
+
# Temporary hack to get CodeClimate to work with SimpleCov 0.18 JSON format until issue is fixed
|
6
|
+
# upstream: https://github.com/codeclimate/test-reporter/issues/413
|
7
|
+
|
8
|
+
require "json"
|
9
|
+
|
10
|
+
filename = "coverage/.resultset.json"
|
11
|
+
contents = JSON.parse(File.read(filename))
|
12
|
+
|
13
|
+
def remove_lines_key(obj)
|
14
|
+
case obj
|
15
|
+
when Hash
|
16
|
+
obj.transform_values do |val|
|
17
|
+
val.is_a?(Hash) && val.key?("lines") ? val["lines"] : remove_lines_key(val)
|
18
|
+
end
|
19
|
+
else
|
20
|
+
obj
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# overwrite
|
25
|
+
File.write(filename, JSON.generate(remove_lines_key(contents)))
|
26
|
+
|
27
|
+
puts Dir['coverage/.*.json']
|
data/bin/test
ADDED
@@ -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 initialize(r, g, b)
|
6
|
+
super(
|
7
|
+
Number.new(value: r, label: 'red'),
|
8
|
+
Number.new(value: g, label: 'green'),
|
9
|
+
Number.new(value: b, label: 'blue')
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_a
|
14
|
+
@to_a ||= super.map(&:value)
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_hex
|
18
|
+
@to_hex ||= "##{red}#{green}#{blue}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RGB
|
4
|
+
Number = Micro::Struct.with(:readonly).new(:value, :label) 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 initialize(value, label)
|
10
|
+
super(Input[value, label: label])
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
@to_s ||= '%02x' % value
|
15
|
+
end
|
16
|
+
|
17
|
+
def inspect
|
18
|
+
"#<RGB::Number #{value}>"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/examples/rgb_1.rb
ADDED
@@ -0,0 +1,53 @@
|
|
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 initialize(r, g, b)
|
18
|
+
super(Number[r], Number[g], Number[b])
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_hex
|
22
|
+
'#%02x%02x%02x' % self
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
puts
|
27
|
+
|
28
|
+
rgb_color = RGBColor.new(red: 1, green: 1, blue: 255)
|
29
|
+
|
30
|
+
p rgb_color
|
31
|
+
|
32
|
+
puts
|
33
|
+
puts format('to_a: %p', rgb_color.to_a)
|
34
|
+
puts format('to_hex: %p', rgb_color.to_hex)
|
35
|
+
puts
|
36
|
+
|
37
|
+
r, g, b = rgb_color
|
38
|
+
|
39
|
+
puts format('red: %p', r)
|
40
|
+
puts format('green: %p', g)
|
41
|
+
puts format('blue: %p', b)
|
42
|
+
puts
|
43
|
+
|
44
|
+
*rgb = rgb_color
|
45
|
+
|
46
|
+
puts rgb.inspect
|
47
|
+
puts
|
48
|
+
|
49
|
+
begin
|
50
|
+
RGBColor.new(red: 1, green: -1, blue: 255)
|
51
|
+
rescue => exception
|
52
|
+
puts exception # Kind::Error (-1 expected to be a kind of Integer(>= 0 and <= 255))
|
53
|
+
end
|
data/examples/rgb_2.rb
ADDED
@@ -0,0 +1,75 @@
|
|
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 initialize(value)
|
18
|
+
super(Input[value])
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
'%02x' % value
|
23
|
+
end
|
24
|
+
|
25
|
+
def inspect
|
26
|
+
"#<RGBNumber #{value}>"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
RGBColor = Micro::Struct.with(:readonly, :to_ary).new(:red, :green, :blue) do
|
31
|
+
def self.new(r:, g:, b:)
|
32
|
+
__new__(
|
33
|
+
red: RGBNumber.new(value: r),
|
34
|
+
green: RGBNumber.new(value: g),
|
35
|
+
blue: RGBNumber.new(value: b)
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_a
|
40
|
+
[red.value, green.value, blue.value]
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_hex
|
44
|
+
"##{red}#{green}#{blue}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
puts
|
49
|
+
|
50
|
+
rgb_color = RGBColor.new(r: 1, g: 1, b: 255)
|
51
|
+
|
52
|
+
p rgb_color
|
53
|
+
|
54
|
+
puts
|
55
|
+
puts format('to_a: %p', rgb_color.to_a)
|
56
|
+
puts format('to_hex: %p', rgb_color.to_hex)
|
57
|
+
puts
|
58
|
+
|
59
|
+
r, g, b = rgb_color
|
60
|
+
|
61
|
+
puts format('red: %p', r)
|
62
|
+
puts format('green: %p', g)
|
63
|
+
puts format('blue: %p', b)
|
64
|
+
puts
|
65
|
+
|
66
|
+
*rgb = rgb_color
|
67
|
+
|
68
|
+
puts rgb.inspect
|
69
|
+
puts
|
70
|
+
|
71
|
+
begin
|
72
|
+
RGBColor.new(r: 1, g: -1, b: 255)
|
73
|
+
rescue => exception
|
74
|
+
puts exception # Kind::Error (-1 expected to be a kind of Integer(>= 0 and <= 255))
|
75
|
+
end
|
data/examples/rgb_3.rb
ADDED
@@ -0,0 +1,42 @@
|
|
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
|
+
puts
|
16
|
+
|
17
|
+
rgb_color = RGB::Color.new(red: 1, green: 1, blue: 255)
|
18
|
+
|
19
|
+
p rgb_color
|
20
|
+
|
21
|
+
puts
|
22
|
+
puts format('to_a: %p', rgb_color.to_a)
|
23
|
+
puts format('to_hex: %p', rgb_color.to_hex)
|
24
|
+
puts
|
25
|
+
|
26
|
+
r, g, b = rgb_color
|
27
|
+
|
28
|
+
puts format('red: %p', r)
|
29
|
+
puts format('green: %p', g)
|
30
|
+
puts format('blue: %p', b)
|
31
|
+
puts
|
32
|
+
|
33
|
+
*rgb = rgb_color
|
34
|
+
|
35
|
+
puts rgb.inspect
|
36
|
+
puts
|
37
|
+
|
38
|
+
begin
|
39
|
+
RGB::Color.new(red: 1, green: -1, blue: 255)
|
40
|
+
rescue => exception
|
41
|
+
puts exception # Kind::Error (green: -1 expected to be a kind of Integer(>= 0 and <= 255))
|
42
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Micro::Struct::Factory
|
4
|
+
module CreateStruct
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def with(members, block, features)
|
8
|
+
struct = ::Struct.new(*members.required_and_optional)
|
9
|
+
|
10
|
+
ClassScope.def_new(struct, members)
|
11
|
+
ClassScope.def_to_proc(struct) if features[:to_proc]
|
12
|
+
ClassScope.def_private_writers(struct) if features[:readonly]
|
13
|
+
|
14
|
+
InstanceScope.def_with(struct) if features[:instance_copy]
|
15
|
+
InstanceScope.def_to_ary(struct) if features[:to_ary]
|
16
|
+
InstanceScope.def_to_hash(struct) if features[:to_hash]
|
17
|
+
|
18
|
+
ClassScope.evaluate(struct, block)
|
19
|
+
|
20
|
+
struct
|
21
|
+
end
|
22
|
+
|
23
|
+
module ClassScope
|
24
|
+
def self.def_new(struct, members)
|
25
|
+
# The .new() method will require all required keyword arguments.
|
26
|
+
# We are doing this because the Struct constructor keyword init option treats everything as optional.
|
27
|
+
#
|
28
|
+
struct.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
29
|
+
class << self
|
30
|
+
undef_method :new
|
31
|
+
|
32
|
+
def new(#{members.to_eval.keyword_args}) # def new(a:, b:, c: nil) do
|
33
|
+
instance = allocate # instance = allocate
|
34
|
+
instance.send(:initialize, #{members.to_eval.positional_args}) # instance.send(:initialize, a, b, c)
|
35
|
+
instance # instance
|
36
|
+
end # end
|
37
|
+
|
38
|
+
alias __new__ new
|
39
|
+
end
|
40
|
+
RUBY
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.def_to_proc(struct)
|
44
|
+
struct.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
45
|
+
def self.to_proc
|
46
|
+
->(hash) { new(**hash) }
|
47
|
+
end
|
48
|
+
RUBY
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.def_private_writers(struct)
|
52
|
+
struct.send(:private, *struct.members.map { |member| "#{member}=" })
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.evaluate(struct, block)
|
56
|
+
struct.class_eval(&block) if block
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module InstanceScope
|
61
|
+
def self.def_to_ary(struct)
|
62
|
+
struct.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
63
|
+
def to_ary
|
64
|
+
to_a
|
65
|
+
end
|
66
|
+
RUBY
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.def_to_hash(struct)
|
70
|
+
struct.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
71
|
+
def to_hash
|
72
|
+
to_h
|
73
|
+
end
|
74
|
+
RUBY
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.def_with(struct)
|
78
|
+
struct.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
79
|
+
def with(**members)
|
80
|
+
self.class.new(**to_h.merge(members))
|
81
|
+
end
|
82
|
+
RUBY
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private_constant :CreateStruct
|
88
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Micro::Struct
|
4
|
+
class Factory
|
5
|
+
class Members
|
6
|
+
attr_reader :required_and_optional
|
7
|
+
|
8
|
+
Names = ->(values) { NormalizeNames::AsSymbols.(values, context: 'member') }
|
9
|
+
|
10
|
+
def initialize(required_members, required_option, optional_option)
|
11
|
+
@required = Names[required_members] + Names[required_option]
|
12
|
+
@optional = Names[optional_option]
|
13
|
+
|
14
|
+
@required_and_optional = @required + @optional
|
15
|
+
end
|
16
|
+
|
17
|
+
ToEval = ::Struct.new(:required, :optional, :required_and_optional) do
|
18
|
+
def keyword_args
|
19
|
+
required_kargs = "#{required.join(':, ')}#{':' unless required.empty?}"
|
20
|
+
optional_kargs = "#{optional.join(': nil, ')}#{': nil' unless optional.empty?}"
|
21
|
+
|
22
|
+
[required_kargs, optional_kargs].reject(&:empty?).join(', ')
|
23
|
+
end
|
24
|
+
|
25
|
+
def positional_args
|
26
|
+
required_and_optional.join(', ')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_eval
|
31
|
+
@to_eval ||= ToEval.new(@required, @optional, required_and_optional)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private_constant :Members
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Micro::Struct
|
4
|
+
class Factory
|
5
|
+
require_relative 'factory/members'
|
6
|
+
require_relative 'factory/create_struct'
|
7
|
+
|
8
|
+
def initialize(features)
|
9
|
+
@features = Features.require(features)
|
10
|
+
end
|
11
|
+
|
12
|
+
def new(*required_members, required: nil, optional: nil, &struct_block)
|
13
|
+
members = Members.new(required_members, required, optional)
|
14
|
+
|
15
|
+
CreateStruct.with(members, struct_block, @features)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private_constant :Factory
|
20
|
+
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,13 +17,12 @@ module Micro::Struct
|
|
18
17
|
instance_copy: instance_copy }
|
19
18
|
end
|
20
19
|
|
21
|
-
|
20
|
+
Names = ->(values) do
|
22
21
|
NormalizeNames::AsSymbols.(values, context: 'feature')
|
23
22
|
end
|
24
23
|
|
25
|
-
def self.require(
|
26
|
-
to_enable =
|
27
|
-
NormalizeFeatureNames[names].each_with_object({}) { |name, memo| memo[name] = true }
|
24
|
+
def self.require(values)
|
25
|
+
to_enable = Names[values].each_with_object({}) { |name, memo| memo[name] = true }
|
28
26
|
|
29
27
|
Check.(**DISABLED.merge(to_enable))
|
30
28
|
end
|
data/lib/micro/struct/version.rb
CHANGED
data/lib/micro/struct.rb
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
require_relative 'struct/version'
|
4
4
|
require_relative 'struct/features'
|
5
|
-
require_relative 'struct/
|
5
|
+
require_relative 'struct/factory'
|
6
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
|
#
|
@@ -62,7 +62,7 @@ module Micro
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def self.with(*features)
|
65
|
-
|
65
|
+
Factory.new(features)
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
data/u-struct.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.description = %q{Create powered Ruby structs.}
|
13
13
|
spec.homepage = 'https://github.com/serradura/u-struct'
|
14
14
|
spec.license = 'MIT'
|
15
|
-
spec.required_ruby_version = '>= 2.
|
15
|
+
spec.required_ruby_version = '>= 2.2.0'
|
16
16
|
|
17
17
|
spec.metadata['homepage_uri'] = spec.homepage
|
18
18
|
spec.metadata['source_code_uri'] = 'https://github.com/serradura/u-struct'
|
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.
|
4
|
+
version: 0.11.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-
|
11
|
+
date: 2021-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -45,20 +45,30 @@ executables: []
|
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
+
- ".github/workflows/ci.yml"
|
48
49
|
- ".gitignore"
|
50
|
+
- ".vscode/settings.json"
|
49
51
|
- CHANGELOG.md
|
50
52
|
- CODE_OF_CONDUCT.md
|
51
53
|
- Gemfile
|
52
|
-
- Gemfile.lock
|
53
54
|
- LICENSE.txt
|
54
55
|
- README.md
|
55
56
|
- Rakefile
|
56
57
|
- bin/console
|
58
|
+
- bin/prepare_coverage
|
57
59
|
- bin/setup
|
60
|
+
- bin/test
|
61
|
+
- examples/person_1.rb
|
62
|
+
- examples/person_2.rb
|
63
|
+
- examples/rgb/color.rb
|
64
|
+
- examples/rgb/number.rb
|
65
|
+
- examples/rgb_1.rb
|
66
|
+
- examples/rgb_2.rb
|
67
|
+
- examples/rgb_3.rb
|
58
68
|
- lib/micro/struct.rb
|
59
|
-
- lib/micro/struct/
|
60
|
-
- lib/micro/struct/
|
61
|
-
- lib/micro/struct/
|
69
|
+
- lib/micro/struct/factory.rb
|
70
|
+
- lib/micro/struct/factory/create_struct.rb
|
71
|
+
- lib/micro/struct/factory/members.rb
|
62
72
|
- lib/micro/struct/features.rb
|
63
73
|
- lib/micro/struct/normalize_names.rb
|
64
74
|
- lib/micro/struct/version.rb
|
@@ -79,14 +89,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
79
89
|
requirements:
|
80
90
|
- - ">="
|
81
91
|
- !ruby/object:Gem::Version
|
82
|
-
version: 2.
|
92
|
+
version: 2.2.0
|
83
93
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
94
|
requirements:
|
85
95
|
- - ">="
|
86
96
|
- !ruby/object:Gem::Version
|
87
97
|
version: '0'
|
88
98
|
requirements: []
|
89
|
-
rubygems_version: 3.2.
|
99
|
+
rubygems_version: 3.2.22
|
90
100
|
signing_key:
|
91
101
|
specification_version: 4
|
92
102
|
summary: Create powered Ruby structs.
|
data/Gemfile.lock
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
u-struct (0.7.0)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
docile (1.4.0)
|
10
|
-
minitest (5.14.4)
|
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)
|
18
|
-
|
19
|
-
PLATFORMS
|
20
|
-
x86_64-darwin-19
|
21
|
-
|
22
|
-
DEPENDENCIES
|
23
|
-
bundler
|
24
|
-
minitest (~> 5.0)
|
25
|
-
rake (~> 13.0)
|
26
|
-
simplecov (~> 0.21.2)
|
27
|
-
u-struct!
|
28
|
-
|
29
|
-
BUNDLED WITH
|
30
|
-
2.2.32
|
@@ -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
|
data/lib/micro/struct/creator.rb
DELETED
@@ -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
|
-
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
|