u-struct 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +5 -5
- data/.rubocop.yml +129 -0
- data/.rubocop_todo.yml +10 -0
- data/.tool-versions +1 -0
- data/CHANGELOG.md +115 -27
- data/Gemfile +14 -3
- data/README.md +166 -62
- data/Rakefile +5 -5
- data/bin/console +3 -3
- data/bin/prepare_coverage +7 -9
- data/bin/run_ci +17 -0
- data/bin/tapioca +28 -0
- data/examples/rgb/number.rb +1 -1
- data/examples/rgb_1.rb +3 -3
- data/examples/rgb_2.rb +2 -2
- data/examples/rgb_3.rb +1 -1
- data/lib/micro/struct/factory/create_struct.rb +12 -5
- data/lib/micro/struct/factory/members.rb +1 -0
- data/lib/micro/struct/factory.rb +10 -5
- data/lib/micro/struct/features.rb +18 -23
- data/lib/micro/struct/normalize_names.rb +4 -3
- data/lib/micro/struct/version.rb +2 -1
- data/lib/micro/struct.rb +32 -5
- data/lib/u-struct.rb +2 -0
- data/rbi/micro/struct/factory/create_struct.rbi +60 -0
- data/rbi/micro/struct/factory/members.rbi +67 -0
- data/rbi/micro/struct/factory.rbi +41 -0
- data/rbi/micro/struct/features.rbi +41 -0
- data/rbi/micro/struct/normalize_names.rbi +20 -0
- data/rbi/micro/struct/version.rbi +3 -0
- data/rbi/micro/struct.rbi +68 -0
- data/sorbet/config +8 -0
- data/sorbet/rbi/gems/ast@2.4.2.rbi +54 -0
- data/sorbet/rbi/gems/coderay@1.1.3.rbi +8 -0
- data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +11 -0
- data/sorbet/rbi/gems/docile@1.4.0.rbi +54 -0
- data/sorbet/rbi/gems/method_source@1.0.0.rbi +8 -0
- data/sorbet/rbi/gems/minitest@5.15.0.rbi +345 -0
- data/sorbet/rbi/gems/parser@3.1.0.0.rbi +1196 -0
- data/sorbet/rbi/gems/pry@0.14.1.rbi +8 -0
- data/sorbet/rbi/gems/rake@13.0.6.rbi +806 -0
- data/sorbet/rbi/gems/rbi@0.0.9.rbi +1602 -0
- data/sorbet/rbi/gems/simplecov-html@0.12.3.rbi +89 -0
- data/sorbet/rbi/gems/simplecov@0.21.2.rbi +577 -0
- data/sorbet/rbi/gems/simplecov_json_formatter@0.1.3.rbi +8 -0
- data/sorbet/rbi/gems/spoom@1.1.8.rbi +1252 -0
- data/sorbet/rbi/gems/tapioca@0.6.2.rbi +1232 -0
- data/sorbet/rbi/gems/thor@1.2.1.rbi +844 -0
- data/sorbet/rbi/gems/unparser@0.6.3.rbi +8 -0
- data/sorbet/rbi/gems/webrick@1.7.0.rbi +601 -0
- data/sorbet/rbi/gems/yard-sorbet@0.6.1.rbi +199 -0
- data/sorbet/rbi/gems/yard@0.9.27.rbi +4112 -0
- data/sorbet/tapioca/config.yml +13 -0
- data/sorbet/tapioca/require.rb +4 -0
- data/u-struct.gemspec +3 -3
- metadata +37 -3
- data/bin/test +0 -8
data/README.md
CHANGED
@@ -22,7 +22,7 @@
|
|
22
22
|
|
23
23
|
# Table of contents: <!-- omit in toc -->
|
24
24
|
- [Introduction](#introduction)
|
25
|
-
- [
|
25
|
+
- [Motivation](#motivation)
|
26
26
|
- [Installation](#installation)
|
27
27
|
- [Usage](#usage)
|
28
28
|
- [`Micro::Struct.new`](#microstructnew)
|
@@ -30,25 +30,30 @@
|
|
30
30
|
- [`required:` option](#required-option)
|
31
31
|
- [Defining custom methods/behavior](#defining-custom-methodsbehavior)
|
32
32
|
- [`Micro::Struct.with`](#microstructwith)
|
33
|
+
- [`Micro::Struct[]`](#microstruct)
|
33
34
|
- [`:to_ary`](#to_ary)
|
34
35
|
- [`:to_hash`](#to_hash)
|
35
36
|
- [`:to_proc`](#to_proc)
|
36
37
|
- [`:readonly`](#readonly)
|
37
38
|
- [`:instance_copy`](#instance_copy)
|
38
39
|
- [`:exposed_features`](#exposed_features)
|
39
|
-
- [`Micro::Struct.instance
|
40
|
+
- [`Micro::Struct.instance` or `Micro::Struct.with(...).instance`](#microstructinstance-or-microstructwithinstance)
|
41
|
+
- [`Micro::Struct.immutable`](#microstructimmutable)
|
42
|
+
- [`Micro::Struct.readonly`](#microstructreadonly)
|
40
43
|
- [TL;DR](#tldr)
|
41
44
|
- [FAQ](#faq)
|
42
|
-
- [How to
|
43
|
-
- [Can I
|
45
|
+
- [How to override the Struct `.new` method?](#how-to-override-the-struct-new-method)
|
46
|
+
- [Can I override the Struct initializer?](#can-i-override-the-struct-initializer)
|
44
47
|
- [Development](#development)
|
45
48
|
- [Contributing](#contributing)
|
46
49
|
- [License](#license)
|
47
50
|
- [Code of Conduct](#code-of-conduct)
|
51
|
+
- [Contact](#contact)
|
52
|
+
- [Acknowledgments](#acknowledgments)
|
48
53
|
|
49
54
|
## Introduction
|
50
55
|
|
51
|
-
Ruby Struct is a versatile data structure because it can behave like an Array
|
56
|
+
Ruby `Struct` is a versatile data structure because it can behave like an `Array`, `Hash`, and ordinary object:
|
52
57
|
|
53
58
|
```ruby
|
54
59
|
Person = Struct.new(:first_name, :last_name)
|
@@ -99,7 +104,7 @@ person.to_a
|
|
99
104
|
# ["John", "Doe"]
|
100
105
|
```
|
101
106
|
|
102
|
-
Because of these characteristics, structs could be excellent candidates to create different kinds of POROs (Plain Old Ruby Objects).
|
107
|
+
Because of these characteristics, structs could be excellent candidates to create different kinds of POROs (Plain Old Ruby Objects). However, it is very common to see developers avoiding its usage because of some of its behaviors, like setters or the constructor's positional arguments. The addition of keywords arguments on its constructor ([available on Ruby >= 2.5](https://www.bigbinary.com/blog/ruby-2-5-allows-creating-structs-with-keyword-arguments)) improved the experience to instantiate `Struct` objects but it doesn't require all the arguments. Some developers can still feel uncomfortable with that and they might avoid its usage.
|
103
108
|
|
104
109
|
Look at the example showing the Struct's `keyword_init:` option creating a constructor with optional keyword arguments:
|
105
110
|
|
@@ -118,9 +123,9 @@ Person.new(foo: 1, bar: 2)
|
|
118
123
|
# ArgumentError (unknown keywords: foo, bar)
|
119
124
|
```
|
120
125
|
|
121
|
-
###
|
126
|
+
### Motivation
|
122
127
|
|
123
|
-
So, given this introduction, the idea of this project is to provide a way of creating Ruby Structs with some [powerful features](#microstructwith).
|
128
|
+
So, given this introduction, the idea of this project is to provide a way of creating Ruby Structs with some [powerful features](#microstructwith). Let's see how the `Micro::Struct.new()` works.
|
124
129
|
|
125
130
|
```ruby
|
126
131
|
require 'u-struct'
|
@@ -136,7 +141,7 @@ Person.new
|
|
136
141
|
|
137
142
|
As you can see, the struct instantiation raised an error because all of the keywords arguments are required.
|
138
143
|
|
139
|
-
|
144
|
+
If you need one or many optional arguments, you can use the `optional:` option to define them:
|
140
145
|
|
141
146
|
```ruby
|
142
147
|
Person = Micro::Struct.new(:first_name, optional: :last_name)
|
@@ -148,9 +153,7 @@ Person.new(first_name: 'Rodrigo')
|
|
148
153
|
# #<struct Person first_name="Rodrigo", last_name=nil>
|
149
154
|
```
|
150
155
|
|
151
|
-
If you want a Struct only with optional members (or attributes), as the `keyword_init:` option does
|
152
|
-
|
153
|
-
You can declare all attributes within the `optional:` option.
|
156
|
+
If you want a `Struct` only with optional members (or attributes), as the `keyword_init:` option does, you can declare all attributes within the optional: option:
|
154
157
|
|
155
158
|
```ruby
|
156
159
|
Person = Micro::Struct.new(optional: [:first_name, :last_name])
|
@@ -186,15 +189,15 @@ Or install it yourself as:
|
|
186
189
|
|
187
190
|
$ gem install u-struct
|
188
191
|
|
189
|
-
|
192
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
190
193
|
|
191
194
|
## Usage
|
192
195
|
|
193
196
|
### `Micro::Struct.new`
|
194
197
|
|
195
|
-
Like `Struct.new`, you will use `Micro::Struct.new` to create your Struct classes.
|
198
|
+
Like `Struct.new`, you will use `Micro::Struct.new` to create your `Struct` classes.
|
196
199
|
|
197
|
-
The key difference is:
|
200
|
+
The key difference is: the `Struct` created from `Micro::Struct` will use keyword arguments in their constructors.
|
198
201
|
|
199
202
|
```ruby
|
200
203
|
Person = Struct.new(:name) # Person
|
@@ -211,11 +214,11 @@ Person.new # #<struct Person name=nil>
|
|
211
214
|
Persona.new # ArgumentError (missing keyword: :name)
|
212
215
|
```
|
213
216
|
|
214
|
-
|
217
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
215
218
|
|
216
219
|
#### `optional:` option
|
217
220
|
|
218
|
-
|
221
|
+
If you need optional attributes, you can use this to define them.
|
219
222
|
|
220
223
|
```ruby
|
221
224
|
Person = Micro::Struct.new(:name, optional: :age)
|
@@ -239,7 +242,7 @@ Person.new(name: 'John')
|
|
239
242
|
# #<struct Person name="John", age=nil, nickname=nil>
|
240
243
|
```
|
241
244
|
|
242
|
-
|
245
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
243
246
|
|
244
247
|
#### `required:` option
|
245
248
|
|
@@ -258,11 +261,11 @@ Person.new first_name: 'John', last_name: 'Doe'
|
|
258
261
|
# #<struct Person first_name="John", last_name="Doe", age=nil>
|
259
262
|
```
|
260
263
|
|
261
|
-
|
264
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
262
265
|
|
263
266
|
#### Defining custom methods/behavior
|
264
267
|
|
265
|
-
The `Micro::Struct.new` accepts a block as a regular Struct
|
268
|
+
The `Micro::Struct.new` accepts a block as a regular `Struct`, and you can use it to define some custom behavior/methods.
|
266
269
|
|
267
270
|
```ruby
|
268
271
|
Person = Micro::Struct.new(:first_name, :last_name, optional: :age) do
|
@@ -279,11 +282,11 @@ person.last_name # "Serradura"
|
|
279
282
|
person.name # "Rodrigo Serradura"
|
280
283
|
```
|
281
284
|
|
282
|
-
|
285
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
283
286
|
|
284
287
|
### `Micro::Struct.with`
|
285
288
|
|
286
|
-
This method can do two things: first, it can create Struct factories; second, it sets some special behavior to their structs.
|
289
|
+
This method can do two things: first, it can create `Struct` factories; second, it sets some special behavior to their structs.
|
287
290
|
|
288
291
|
These are all of the available features which you can use (pick one, many, or all of them):
|
289
292
|
- [`:to_ary`](#to_ary)
|
@@ -293,31 +296,53 @@ These are all of the available features which you can use (pick one, many, or al
|
|
293
296
|
- [`:instance_copy`](#instance_copy)
|
294
297
|
- [`:exposed_features`](#exposed_features)
|
295
298
|
|
299
|
+
Look at an example of defining a `Struct` factory that can create "immutable" structs by picking the `:readonly`, `:instance_copy` features.
|
300
|
+
|
296
301
|
```ruby
|
297
302
|
ReadonlyStruct = Micro::Struct.with(:readonly, :instance_copy)
|
298
303
|
|
299
|
-
|
304
|
+
# Use the factory to create structs with the same characteristics:
|
300
305
|
|
301
|
-
Person.new
|
306
|
+
Person = ReadonlyStruct.new(:first_name, :last_name)
|
302
307
|
|
303
308
|
person = Person.new(first_name: 'Rodrigo', last_name: 'Rodrigues')
|
304
309
|
# #<struct Person first_name="Rodrigo", last_name="Rodrigues">
|
305
310
|
|
311
|
+
# The `:readonly` sets all the Struct writers as private.
|
312
|
+
|
306
313
|
person.last_name = ''
|
307
314
|
# NoMethodError (private method `last_name=' called for #<struct Person ...>)
|
308
315
|
|
309
316
|
person[:last_name] = ''
|
310
317
|
# NoMethodError (private method `[]=' called for #<struct Person ...>)
|
311
318
|
|
312
|
-
|
319
|
+
# The `:instance_copy` defines a `#with` instance method,
|
320
|
+
# which allows you to create a new instance from the current struct state.
|
321
|
+
|
322
|
+
new_person = person.with(last_name: 'Serradura')
|
313
323
|
# #<struct Person first_name="Rodrigo", last_name="Serradura">
|
324
|
+
|
325
|
+
new_person == person
|
326
|
+
# false
|
327
|
+
|
328
|
+
new_person.class == person.class
|
329
|
+
# true
|
314
330
|
```
|
315
331
|
|
316
|
-
|
332
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
333
|
+
|
334
|
+
### `Micro::Struct[]`
|
335
|
+
|
336
|
+
The `[]` brackets method is as an alias of `Micro::Struct.with`. e.g.
|
337
|
+
```ruby
|
338
|
+
Micro::Struct[:readonly, :to_hash] # is the same as Micro::Struct.with(:readonly, :to_hash)
|
339
|
+
```
|
340
|
+
|
341
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
317
342
|
|
318
343
|
#### `:to_ary`
|
319
344
|
|
320
|
-
Defines a `#to_ary` method which will invoke the struct `#to_a` method
|
345
|
+
Defines a `#to_ary` method which will invoke the struct `#to_a` method. If you override the `#to_a` method you will also affect it.
|
321
346
|
|
322
347
|
The `#to_ary` makes Ruby know how to deconstruct an object like an array.
|
323
348
|
|
@@ -336,11 +361,11 @@ p last_name # "Serradura"
|
|
336
361
|
p first_and_last_name # ["Rodrigo", "Serradura"]
|
337
362
|
```
|
338
363
|
|
339
|
-
|
364
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
340
365
|
|
341
366
|
#### `:to_hash`
|
342
367
|
|
343
|
-
Defines a `#to_hash` method which will invoke the struct `#to_h` method
|
368
|
+
Defines a `#to_hash` method which will invoke the struct `#to_h` method. If you override the `#to_h` method you will also affect it.
|
344
369
|
|
345
370
|
The `#to_hash` makes Ruby know how to deconstruct an object like a hash.
|
346
371
|
|
@@ -357,7 +382,7 @@ greet(**person)
|
|
357
382
|
# Hi Rodrigo Serradura!
|
358
383
|
```
|
359
384
|
|
360
|
-
|
385
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
361
386
|
|
362
387
|
#### `:to_proc`
|
363
388
|
|
@@ -378,7 +403,7 @@ Person = Micro::Struct.with(:to_proc).new(:first_name, :last_name)
|
|
378
403
|
# ]
|
379
404
|
```
|
380
405
|
|
381
|
-
|
406
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
382
407
|
|
383
408
|
#### `:readonly`
|
384
409
|
|
@@ -397,7 +422,7 @@ person[:last_name] = ''
|
|
397
422
|
# NoMethodError (private method `[]=' called for #<struct Person ...>)
|
398
423
|
```
|
399
424
|
|
400
|
-
|
425
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
401
426
|
|
402
427
|
#### `:instance_copy`
|
403
428
|
|
@@ -425,7 +450,7 @@ person.last_name # => "Serradura"
|
|
425
450
|
new_person.last_name # => "Doe"
|
426
451
|
```
|
427
452
|
|
428
|
-
|
453
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
429
454
|
|
430
455
|
#### `:exposed_features`
|
431
456
|
|
@@ -454,9 +479,9 @@ Person.features.options?(:to_proc, :readonly) # => true
|
|
454
479
|
Person.features.options?(:to_ary, :readonly) # => false
|
455
480
|
```
|
456
481
|
|
457
|
-
|
482
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
458
483
|
|
459
|
-
### `Micro::Struct.instance
|
484
|
+
### `Micro::Struct.instance` or `Micro::Struct.with(...).instance`
|
460
485
|
|
461
486
|
Creates a struct instance from a given hash. This could be useful to create constants or a singleton value.
|
462
487
|
|
@@ -498,18 +523,78 @@ person3.name # => "Rodrigo Serradura"
|
|
498
523
|
person4.name # => "Rodrigo Serradura"
|
499
524
|
```
|
500
525
|
|
501
|
-
|
526
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
527
|
+
|
528
|
+
### `Micro::Struct.immutable`
|
529
|
+
|
530
|
+
This method is as a shortcut to `Micro::Struct.with(:readonly, :instance_copy)`.
|
531
|
+
As it is quite common to see the usage of these two features, I decided to create this method to improve the DX.
|
532
|
+
|
533
|
+
Additional info:
|
534
|
+
1. It accepts the `with:` option, which can be used to define additional features.
|
535
|
+
2. The `.instance` method can be called after its usage.
|
536
|
+
|
537
|
+
Usage examples:
|
538
|
+
|
539
|
+
```ruby
|
540
|
+
Micro::Struct.immutable.new(:name)
|
541
|
+
|
542
|
+
Micro::Struct.immutable.new(:name) do
|
543
|
+
def hi(other_name)
|
544
|
+
"Hi, #{other_name}! My name is #{name}"
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
Micro::Struct.immutable(with: :to_hash).new(:name)
|
549
|
+
|
550
|
+
Micro::Struct.immutable(with: [:to_hash, :to_proc]).new(:name)
|
551
|
+
|
552
|
+
Micro::Struct.immutable.instance(name: 'Rodrigo')
|
553
|
+
|
554
|
+
Micro::Struct.immutable(with: [:to_hash]).instance(name: 'Serradura')
|
555
|
+
```
|
556
|
+
|
557
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
558
|
+
|
559
|
+
### `Micro::Struct.readonly`
|
560
|
+
|
561
|
+
This method is as a shortcut to `Micro::Struct.with(:readonly)`.
|
562
|
+
|
563
|
+
Additional info:
|
564
|
+
1. It accepts the `with:` option, which can be used to define additional features.
|
565
|
+
2. The `.instance` method can be called after its usage.
|
566
|
+
|
567
|
+
Usage examples:
|
568
|
+
|
569
|
+
```ruby
|
570
|
+
Micro::Struct.readonly.new(:name)
|
571
|
+
|
572
|
+
Micro::Struct.readonly.new(:name) do
|
573
|
+
def hi(other_name)
|
574
|
+
"Hi, #{other_name}! My name is #{name}"
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
Micro::Struct.readonly(with: :to_hash).new(:name)
|
579
|
+
|
580
|
+
Micro::Struct.readonly(with: [:to_hash, :to_proc]).new(:name)
|
581
|
+
|
582
|
+
Micro::Struct.readonly.instance(name: 'Rodrigo')
|
583
|
+
|
584
|
+
Micro::Struct.readonly(with: [:to_hash]).instance(name: 'Serradura')
|
585
|
+
```
|
586
|
+
|
587
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
502
588
|
|
503
589
|
### TL;DR
|
504
590
|
|
505
|
-
Like in a regular Struct
|
506
|
-
But all of them will be required by default.
|
591
|
+
Like in a regular `Struct`, you can define one or many attributes but all of them will be required by default.
|
507
592
|
|
508
593
|
```ruby
|
509
594
|
Micro::Struct.new(:first_name, :last_name, ...)
|
510
595
|
```
|
511
596
|
|
512
|
-
Use the `optional:`
|
597
|
+
Use the `optional:` argument if you want some optional attributes.
|
513
598
|
|
514
599
|
```ruby
|
515
600
|
Micro::Struct.new(:first_name, :last_name, optional: :gender)
|
@@ -519,7 +604,7 @@ Micro::Struct.new(:first_name, :last_name, optional: :gender)
|
|
519
604
|
Micro::Struct.new(optional: [:first_name, :last_name])
|
520
605
|
```
|
521
606
|
|
522
|
-
Use the `required:`
|
607
|
+
Use the `required:` argument to define required attributes.
|
523
608
|
|
524
609
|
```ruby
|
525
610
|
Micro::Struct.new(
|
@@ -572,45 +657,50 @@ Micro::Struct.with(*features).new(...) {}
|
|
572
657
|
|
573
658
|
Use `Micro::Struct.instance()` or `Micro::Struct.with(...).instance()` to create a struct instance from a given hash.
|
574
659
|
|
575
|
-
|
660
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
576
661
|
|
577
662
|
## FAQ
|
578
663
|
|
579
|
-
### How to
|
664
|
+
### How to override the Struct `.new` method?
|
580
665
|
|
581
|
-
The `.new` is an alias for the `.__new__` method, so you can use `.__new__` when
|
666
|
+
The `.new` is an alias for the `.__new__` method, so you can use `.__new__` when overriding it.
|
582
667
|
|
583
668
|
```ruby
|
584
669
|
module RGB
|
585
|
-
Number =
|
670
|
+
Number = ->(value) do
|
671
|
+
return value if value.is_a?(::Integer) && value >= 0 && value <= 255
|
586
672
|
|
587
|
-
|
588
|
-
def to_hex
|
589
|
-
"##{red}#{green}#{blue}"
|
590
|
-
end
|
673
|
+
raise TypeError, "#{value} must be an Integer(>= 0 and <= 255)"
|
591
674
|
end
|
592
675
|
|
593
|
-
|
676
|
+
Color = Micro::Struct.new(:red, :green, :blue) do
|
594
677
|
def self.new(r, g, b)
|
595
678
|
__new__(
|
596
|
-
red: Number
|
597
|
-
green: Number
|
598
|
-
blue: Number
|
679
|
+
red: Number[r],
|
680
|
+
green: Number[g],
|
681
|
+
blue: Number[b],
|
599
682
|
)
|
600
683
|
end
|
684
|
+
|
685
|
+
def to_hex
|
686
|
+
"##{red}#{green}#{blue}"
|
687
|
+
end
|
601
688
|
end
|
602
689
|
end
|
603
690
|
|
604
|
-
rgb_color = RGB::Color.new(1,5,255)
|
691
|
+
rgb_color = RGB::Color.new(1, 5, 255)
|
605
692
|
# => #<struct RGB::Color::Struct red=#<struct RGB::Number value=1>, green=#<struct RGB::Number value=5>, blue=#<struct RGB::Number value=255>>
|
606
693
|
|
607
694
|
rgb_color.to_hex
|
608
695
|
# => "#0105ff"
|
696
|
+
|
697
|
+
RGB::Color.new(-1, 5, 255)
|
698
|
+
# => TypeError: -1 must be an Integer(>= 0 and <= 255)
|
609
699
|
```
|
610
700
|
|
611
|
-
|
701
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
612
702
|
|
613
|
-
### Can I
|
703
|
+
### Can I override the Struct initializer?
|
614
704
|
|
615
705
|
Yes, you can, but the initializer must handle the arguments as positional ones.
|
616
706
|
|
@@ -646,30 +736,44 @@ RGBColor.new(red: 1, green: -1, blue: 255)
|
|
646
736
|
# TypeError (-1 must be an Integer(>= 0 and <= 255))
|
647
737
|
```
|
648
738
|
|
649
|
-
|
739
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
650
740
|
|
651
741
|
## Development
|
652
742
|
|
653
743
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
654
744
|
|
745
|
+
Additional tools:
|
746
|
+
- Sorbet (type checker): `bundle exec srb tc` (requires `Ruby >= 2.7`).
|
747
|
+
- Rubocop (linter and code formatter): `bundle rubocop` (requires `Ruby >= 2.5`).
|
748
|
+
|
655
749
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
656
750
|
|
657
|
-
|
751
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
658
752
|
|
659
753
|
## Contributing
|
660
754
|
|
661
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/serradura/u-struct. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/serradura/u-struct/blob/
|
755
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/serradura/u-struct. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/serradura/u-struct/blob/main/CODE_OF_CONDUCT.md).
|
662
756
|
|
663
|
-
|
757
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
664
758
|
|
665
759
|
## License
|
666
760
|
|
667
761
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
668
762
|
|
669
|
-
|
763
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
670
764
|
|
671
765
|
## Code of Conduct
|
672
766
|
|
673
|
-
Everyone interacting in the Micro::Struct project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/serradura/u-struct/blob/
|
767
|
+
Everyone interacting in the `Micro::Struct` project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/serradura/u-struct/blob/main/CODE_OF_CONDUCT.md).
|
768
|
+
|
769
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
770
|
+
|
771
|
+
## Contact
|
772
|
+
|
773
|
+
Rodrigo Serradura - [Twitter](https://twitter.com/serradura) | [LinkedIn](https://www.linkedin.com/in/rodrigo-serradura/).
|
774
|
+
|
775
|
+
<p align="right">(<a href="#table-of-contents-">⬆️ back to top</a>)</p>
|
776
|
+
|
777
|
+
## Acknowledgments
|
674
778
|
|
675
|
-
[
|
779
|
+
- [`@vitoravelino`](https://github.com/vitoravelino) thanks for talking about some gem's ideas and reviewing the documentation.
|
data/Rakefile
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'rake/testtask'
|
5
5
|
|
6
6
|
Rake::TestTask.new(:test) do |t|
|
7
|
-
t.libs <<
|
8
|
-
t.libs <<
|
9
|
-
t.test_files = FileList[
|
7
|
+
t.libs << 'test'
|
8
|
+
t.libs << 'lib'
|
9
|
+
t.test_files = FileList['test/**/*_test.rb']
|
10
10
|
end
|
11
11
|
|
12
12
|
task default: :test
|
data/bin/console
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'micro/struct'
|
6
6
|
|
7
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
8
8
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -11,5 +11,5 @@ require "micro/struct"
|
|
11
11
|
# require "pry"
|
12
12
|
# Pry.start
|
13
13
|
|
14
|
-
require
|
14
|
+
require 'irb'
|
15
15
|
IRB.start(__FILE__)
|
data/bin/prepare_coverage
CHANGED
@@ -1,23 +1,21 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
|
+
|
3
4
|
# Borrowed from https://gist.github.com/qortex/7e7c49f3731391a91ee898336183acef
|
4
5
|
|
5
6
|
# Temporary hack to get CodeClimate to work with SimpleCov 0.18 JSON format until issue is fixed
|
6
7
|
# upstream: https://github.com/codeclimate/test-reporter/issues/413
|
7
8
|
|
8
|
-
require
|
9
|
+
require 'json'
|
9
10
|
|
10
|
-
filename =
|
11
|
+
filename = 'coverage/.resultset.json'
|
11
12
|
contents = JSON.parse(File.read(filename))
|
12
13
|
|
13
14
|
def remove_lines_key(obj)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
19
|
-
else
|
20
|
-
obj
|
15
|
+
return obj unless obj.is_a?(Hash)
|
16
|
+
|
17
|
+
obj.transform_values do |val|
|
18
|
+
val.is_a?(Hash) && val.key?('lines') ? val['lines'] : remove_lines_key(val)
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
data/bin/run_ci
ADDED
data/bin/tapioca
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'tapioca' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
require 'pathname'
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', Pathname.new(__FILE__).realpath)
|
13
|
+
|
14
|
+
bundle_binstub = File.expand_path('bundle', __dir__)
|
15
|
+
|
16
|
+
if File.file?(bundle_binstub)
|
17
|
+
if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
|
18
|
+
load(bundle_binstub)
|
19
|
+
else
|
20
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
21
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'rubygems'
|
26
|
+
require 'bundler/setup'
|
27
|
+
|
28
|
+
load Gem.bin_path('tapioca', 'tapioca')
|
data/examples/rgb/number.rb
CHANGED
data/examples/rgb_1.rb
CHANGED
@@ -12,7 +12,7 @@ RGBColor = Micro::Struct.with(:readonly, :to_ary).new(:red, :green, :blue) do
|
|
12
12
|
Number = ->(value) do
|
13
13
|
return value if value.is_a?(::Integer) && value >= 0 && value <= 255
|
14
14
|
|
15
|
-
raise TypeError
|
15
|
+
raise TypeError.new("#{value} must be an Integer(>= 0 and <= 255)")
|
16
16
|
end
|
17
17
|
|
18
18
|
def initialize(r, g, b)
|
@@ -20,7 +20,7 @@ RGBColor = Micro::Struct.with(:readonly, :to_ary).new(:red, :green, :blue) do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def to_hex
|
23
|
-
'
|
23
|
+
format('#%<r>02x%<g>02x%<b>02x', r: red, g: green, b: blue)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -49,6 +49,6 @@ puts
|
|
49
49
|
|
50
50
|
begin
|
51
51
|
RGBColor.new(red: 1, green: -1, blue: 255)
|
52
|
-
rescue => exception
|
52
|
+
rescue TypeError => exception
|
53
53
|
puts exception # TypeError (-1 must be an Integer(>= 0 and <= 255))
|
54
54
|
end
|
data/examples/rgb_2.rb
CHANGED
@@ -19,7 +19,7 @@ RGBNumber = Micro::Struct.with(:readonly).new(:value) do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def to_s
|
22
|
-
'%02x'
|
22
|
+
format('%02x', value)
|
23
23
|
end
|
24
24
|
|
25
25
|
def inspect
|
@@ -70,6 +70,6 @@ puts
|
|
70
70
|
|
71
71
|
begin
|
72
72
|
RGBColor.new(r: 1, g: -1, b: 255)
|
73
|
-
rescue => exception
|
73
|
+
rescue Kind::Error => exception
|
74
74
|
puts exception # Kind::Error (-1 expected to be a kind of Integer(>= 0 and <= 255))
|
75
75
|
end
|