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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +5 -5
  3. data/.rubocop.yml +129 -0
  4. data/.rubocop_todo.yml +10 -0
  5. data/.tool-versions +1 -0
  6. data/CHANGELOG.md +115 -27
  7. data/Gemfile +14 -3
  8. data/README.md +166 -62
  9. data/Rakefile +5 -5
  10. data/bin/console +3 -3
  11. data/bin/prepare_coverage +7 -9
  12. data/bin/run_ci +17 -0
  13. data/bin/tapioca +28 -0
  14. data/examples/rgb/number.rb +1 -1
  15. data/examples/rgb_1.rb +3 -3
  16. data/examples/rgb_2.rb +2 -2
  17. data/examples/rgb_3.rb +1 -1
  18. data/lib/micro/struct/factory/create_struct.rb +12 -5
  19. data/lib/micro/struct/factory/members.rb +1 -0
  20. data/lib/micro/struct/factory.rb +10 -5
  21. data/lib/micro/struct/features.rb +18 -23
  22. data/lib/micro/struct/normalize_names.rb +4 -3
  23. data/lib/micro/struct/version.rb +2 -1
  24. data/lib/micro/struct.rb +32 -5
  25. data/lib/u-struct.rb +2 -0
  26. data/rbi/micro/struct/factory/create_struct.rbi +60 -0
  27. data/rbi/micro/struct/factory/members.rbi +67 -0
  28. data/rbi/micro/struct/factory.rbi +41 -0
  29. data/rbi/micro/struct/features.rbi +41 -0
  30. data/rbi/micro/struct/normalize_names.rbi +20 -0
  31. data/rbi/micro/struct/version.rbi +3 -0
  32. data/rbi/micro/struct.rbi +68 -0
  33. data/sorbet/config +8 -0
  34. data/sorbet/rbi/gems/ast@2.4.2.rbi +54 -0
  35. data/sorbet/rbi/gems/coderay@1.1.3.rbi +8 -0
  36. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +11 -0
  37. data/sorbet/rbi/gems/docile@1.4.0.rbi +54 -0
  38. data/sorbet/rbi/gems/method_source@1.0.0.rbi +8 -0
  39. data/sorbet/rbi/gems/minitest@5.15.0.rbi +345 -0
  40. data/sorbet/rbi/gems/parser@3.1.0.0.rbi +1196 -0
  41. data/sorbet/rbi/gems/pry@0.14.1.rbi +8 -0
  42. data/sorbet/rbi/gems/rake@13.0.6.rbi +806 -0
  43. data/sorbet/rbi/gems/rbi@0.0.9.rbi +1602 -0
  44. data/sorbet/rbi/gems/simplecov-html@0.12.3.rbi +89 -0
  45. data/sorbet/rbi/gems/simplecov@0.21.2.rbi +577 -0
  46. data/sorbet/rbi/gems/simplecov_json_formatter@0.1.3.rbi +8 -0
  47. data/sorbet/rbi/gems/spoom@1.1.8.rbi +1252 -0
  48. data/sorbet/rbi/gems/tapioca@0.6.2.rbi +1232 -0
  49. data/sorbet/rbi/gems/thor@1.2.1.rbi +844 -0
  50. data/sorbet/rbi/gems/unparser@0.6.3.rbi +8 -0
  51. data/sorbet/rbi/gems/webrick@1.7.0.rbi +601 -0
  52. data/sorbet/rbi/gems/yard-sorbet@0.6.1.rbi +199 -0
  53. data/sorbet/rbi/gems/yard@0.9.27.rbi +4112 -0
  54. data/sorbet/tapioca/config.yml +13 -0
  55. data/sorbet/tapioca/require.rb +4 -0
  56. data/u-struct.gemspec +3 -3
  57. metadata +37 -3
  58. 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
- - [Project Motivation](#project-motivation)
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()` or `Micro::Struct.with(...).instance()`](#microstructinstance-or-microstructwithinstance)
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 overwrite the Struct `.new` method?](#how-to-overwrite-the-struct-new-method)
43
- - [Can I overwrite the Struct initializer?](#can-i-overwrite-the-struct-initializer)
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, Hash, and ordinary object. e.g.
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). But, 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, as it doesn't require all the arguments, some developers can still avoid its usage.
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
- ### Project Motivation
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). And to start, let's see how the `Micro::Struct.new()` works.
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
- But, if you need one or many optional arguments, you can use the `optional:` option to define them. e.g.
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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
192
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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: Structs created from `Micro::Struct` will use keyword arguments in their constructors.
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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
217
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;back to top</a>)</p>
215
218
 
216
219
  #### `optional:` option
217
220
 
218
- But if you need optional attributes, you can use this to define them.
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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
245
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
264
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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, and you can use it to define some custom behavior/methods.
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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
285
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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
- Person = ReadonlyStruct.new(:first_name, :last_name)
304
+ # Use the factory to create structs with the same characteristics:
300
305
 
301
- Person.new # ArgumentError (missing keywords: :first_name, :last_name)
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
- person.with(last_name: 'Serradura')
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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
332
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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-">⬆️ &nbsp;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, so if you overwrite the `#to_a` method you will also affect it.
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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
364
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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, so if you overwrite the `#to_a` method you will also affect it.
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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
385
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
406
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
425
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
453
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
482
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;back to top</a>)</p>
458
483
 
459
- ### `Micro::Struct.instance()` or `Micro::Struct.with(...).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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
526
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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-">⬆️ &nbsp;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-">⬆️ &nbsp;back to top</a>)</p>
502
588
 
503
589
  ### TL;DR
504
590
 
505
- Like in a regular Struct, you can define one or many attributes.
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:` arg if you want some optional attributes.
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:` arg to define required attributes.
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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
660
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;back to top</a>)</p>
576
661
 
577
662
  ## FAQ
578
663
 
579
- ### How to overwrite the Struct `.new` method?
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 overwriting it.
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 = ::Struct.new(:value) { def to_s; '%02x' % value; end }
670
+ Number = ->(value) do
671
+ return value if value.is_a?(::Integer) && value >= 0 && value <= 255
586
672
 
587
- Color = Micro::Struct.new(:red, :green, :blue) do
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
- module Color
676
+ Color = Micro::Struct.new(:red, :green, :blue) do
594
677
  def self.new(r, g, b)
595
678
  __new__(
596
- red: Number.new(r),
597
- green: Number.new(g),
598
- blue: Number.new(b),
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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
701
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;back to top</a>)</p>
612
702
 
613
- ### Can I overwrite the Struct initializer?
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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
739
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
751
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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/master/CODE_OF_CONDUCT.md).
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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
757
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
763
+ <p align="right">(<a href="#table-of-contents-">⬆️ &nbsp;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/master/CODE_OF_CONDUCT.md).
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-">⬆️ &nbsp;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-">⬆️ &nbsp;back to top</a>)</p>
776
+
777
+ ## Acknowledgments
674
778
 
675
- [⬆️ &nbsp;Back to Top](#table-of-contents-)
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 "bundler/gem_tasks"
4
- require "rake/testtask"
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
5
 
6
6
  Rake::TestTask.new(:test) do |t|
7
- t.libs << "test"
8
- t.libs << "lib"
9
- t.test_files = FileList["test/**/*_test.rb"]
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 "bundler/setup"
5
- require "micro/struct"
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 "irb"
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 "json"
9
+ require 'json'
9
10
 
10
- filename = "coverage/.resultset.json"
11
+ filename = 'coverage/.resultset.json'
11
12
  contents = JSON.parse(File.read(filename))
12
13
 
13
14
  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
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
@@ -0,0 +1,17 @@
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ RUBY_V=$(ruby -v)
6
+ RUBY_3_1="ruby 3.1."
7
+
8
+ rm Gemfile.lock
9
+
10
+ bundle install
11
+
12
+ if [[ $RUBY_V =~ $RUBY_3_1 ]]; then
13
+ bundle exec srb tc
14
+ bundle exec rubocop
15
+ fi
16
+
17
+ bundle exec rake test
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')
@@ -11,7 +11,7 @@ module RGB
11
11
  end
12
12
 
13
13
  def to_s
14
- @to_s ||= '%02x' % value
14
+ @to_s ||= format('%02x', value)
15
15
  end
16
16
 
17
17
  def inspect
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, "#{value} must be an Integer(>= 0 and <= 255)"
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
- '#%02x%02x%02x' % self
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' % value
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
data/examples/rgb_3.rb CHANGED
@@ -37,6 +37,6 @@ puts
37
37
 
38
38
  begin
39
39
  RGB::Color.new(red: 1, green: -1, blue: 255)
40
- rescue => exception
40
+ rescue Kind::Error => exception
41
41
  puts exception # Kind::Error (green: -1 expected to be a kind of Integer(>= 0 and <= 255))
42
42
  end