trinkets 0.3.0 → 0.4.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/CHANGELOG.md +6 -0
- data/README.md +16 -1
- data/doc/class/init.md +31 -0
- data/lib/explicit/trinkets/extend/class/init.rb +75 -47
- data/lib/trinkets/version.rb +1 -1
- metadata +35 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b95bff0eaa948f0edc0375709fd3ec786ad10e970f5b5abcd501247dceb1e74
|
4
|
+
data.tar.gz: 3d4d1bce01e034167209cad41d9bf4ad356d79ddf100cfc1968d16b9686a06f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5b3a7cc743fae16ee12cfab9d9efc4236b31d69d8a570fe1bbf009cc3558be08d3cef3a38aa110403fb40dea019a3236adbf4a00c983c5f1f4e148a909bfb884
|
7
|
+
data.tar.gz: e94881a3dc54ca93be7ea759b0b6aff8607b9d91d7d1247d3ec2f59d265ecb2ea4c7f014754ca9a4a351ee6994eabb2fcae0e93fe0d14d27a46b01985370c3f6
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
|
2
|
+
### [0.4.0](https://github.com/SilverPhoenix99/trinkets/tree/v0.4.0)
|
3
|
+
* `Class::init`: Allow default values for keyword arguments.
|
4
|
+
|
5
|
+
### [0.3.1](https://github.com/SilverPhoenix99/trinkets/tree/v0.3.1)
|
6
|
+
* Fixed repeated arguments in `Class::init`.
|
7
|
+
|
2
8
|
### [0.3.0](https://github.com/SilverPhoenix99/trinkets/tree/v0.3.0)
|
3
9
|
* Restructured folders to default to `/refine/`.
|
4
10
|
* Added `Enumerable#each_with_hash`/`Enumerator#with_hash`.
|
data/README.md
CHANGED
@@ -4,10 +4,16 @@ It's the bootleg [facets](https://github.com/rubyworks/facets?tab=readme-ov-file
|
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
+
### RubyGems
|
7
8
|
```
|
8
9
|
gem install trinkets
|
9
10
|
```
|
10
11
|
|
12
|
+
### Bundler
|
13
|
+
```ruby
|
14
|
+
gem 'trinkets', require: false
|
15
|
+
```
|
16
|
+
|
11
17
|
## Usage
|
12
18
|
|
13
19
|
The trinkets are loaded with the following structure:
|
@@ -34,7 +40,7 @@ The `refine` subdirectory is the default, and it can be omitted from `require`.
|
|
34
40
|
require 'trinkets/refine/class/init'
|
35
41
|
```
|
36
42
|
|
37
|
-
### Extend
|
43
|
+
### Extend / Include
|
38
44
|
|
39
45
|
```ruby
|
40
46
|
require 'trinkets/extend/class/init'
|
@@ -44,6 +50,15 @@ class Test
|
|
44
50
|
end
|
45
51
|
```
|
46
52
|
|
53
|
+
```ruby
|
54
|
+
require 'trinkets/include/enumerable/each_with_hash'
|
55
|
+
|
56
|
+
class Test
|
57
|
+
include Enumerable
|
58
|
+
include ::Trinkets::Enumerable::WithHash
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
47
62
|
### Mokey Patching
|
48
63
|
|
49
64
|
```ruby
|
data/doc/class/init.md
CHANGED
@@ -9,6 +9,10 @@ To use it, define a class and call `::init` like you would call `::attr` methods
|
|
9
9
|
* can be `:accessor`, `:reader`, `:writer` or `:none`
|
10
10
|
* defaults to `:accessor`
|
11
11
|
* `kw` : if arguments are to be set as keyword arguments
|
12
|
+
* when `false`, it's a mandatory positional argument
|
13
|
+
* when `true`, it becomes a mandatory keyword argument, like `(a:)`
|
14
|
+
* when it's a hash, like `{ default: <VALUE> }`, it's an optional keyword argument
|
15
|
+
* an empty hash `{}` is equivalent to `{ default: nil }`
|
12
16
|
* defaults to `false`
|
13
17
|
|
14
18
|
The same options can be used per individual argument.
|
@@ -147,6 +151,33 @@ test.a = 5
|
|
147
151
|
# => raises NoMethodError
|
148
152
|
```
|
149
153
|
|
154
|
+
## Default values for keyword arguments
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
class TestDefaultKw
|
158
|
+
init [:a, kw: true],
|
159
|
+
:b,
|
160
|
+
kw: {default: 3}
|
161
|
+
end
|
162
|
+
|
163
|
+
# would be the same as
|
164
|
+
class TestDefaultKw
|
165
|
+
attr_accessor :a, :b
|
166
|
+
def initialize(a: , b: 3)
|
167
|
+
@a = a
|
168
|
+
@b = b
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
test = TestDefaultKw.new(a: 2)
|
173
|
+
|
174
|
+
test.a
|
175
|
+
# 2
|
176
|
+
|
177
|
+
test.b
|
178
|
+
# 3
|
179
|
+
```
|
180
|
+
|
150
181
|
## Mixed together
|
151
182
|
```ruby
|
152
183
|
class TestMixed
|
@@ -6,22 +6,9 @@ module Trinkets
|
|
6
6
|
ATTR = %i[accessor reader writer none].freeze
|
7
7
|
|
8
8
|
def init(*attrs, attr: ATTR.first, kw: false)
|
9
|
-
|
10
|
-
raise ArgumentError, '`attr` must be one of :accessor (default), :reader, :writer or :none' unless ATTR.include?(attr)
|
11
|
-
|
12
|
-
default_attr_options = { attr: attr, kw: kw }
|
13
|
-
|
14
|
-
# Normalize attrs into a hash: { :name => **options }
|
15
|
-
# @type [Hash[Symbol, Hash]]
|
16
|
-
attrs = attrs.map { |a| [*a] }
|
17
|
-
.map { |a| a.size == 1 ? a << {} : a }
|
18
|
-
.each_with_object({}) do |(name, opts), h|
|
19
|
-
# name, opts = a
|
20
|
-
name = name.to_s.sub(/^@/, '').to_sym
|
21
|
-
opts = default_attr_options.merge(opts)
|
22
|
-
h[name] = opts
|
23
|
-
end
|
9
|
+
attrs = Init.send(:sanitize_attrs, attrs, attr: attr, kw: kw)
|
24
10
|
|
11
|
+
# @type [Hash[Symbol, Method]]
|
25
12
|
attr_methods = (ATTR - [:none])
|
26
13
|
.each_with_object({}) do |name, h|
|
27
14
|
h[name] = method("attr_#{name}")
|
@@ -30,57 +17,98 @@ module Trinkets
|
|
30
17
|
# even though options like `kw` aren't used, they serve here to validate the `attrs` options
|
31
18
|
attr_init = ->(name, attr: ATTR.first, kw: false) do
|
32
19
|
unless ATTR.include?(attr)
|
33
|
-
raise ArgumentError, "attr `#{name}
|
20
|
+
raise ArgumentError, "wrong `attr` type for `#{name.inspect}` (given #{attr.inspect}, expected :accessor (default), :reader, :writer or :none)"
|
34
21
|
end
|
35
22
|
attr_methods[attr].call(name) unless attr == :none
|
36
23
|
end
|
37
24
|
|
38
25
|
attrs.each { |name, opts| attr_init.call(name, **opts) }
|
39
26
|
|
40
|
-
#
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
27
|
+
# hash with 3 keys: {
|
28
|
+
# FalseClass => [] # positional args
|
29
|
+
# TrueClass => [] # mandatory kw args
|
30
|
+
# Hash => [] # optional kw args with default value
|
31
|
+
# }
|
32
|
+
grouped_params = attrs
|
33
|
+
.map { |name, opts| [name, opts[:kw] || false] }
|
34
|
+
.group_by { _1.last.class }
|
35
|
+
|
36
|
+
pos_params = [*grouped_params[FalseClass]].map(&:first)
|
37
|
+
kw_params = [*grouped_params[TrueClass]].map(&:first)
|
38
|
+
opt_kw_params = [*grouped_params[Hash]].to_h
|
39
|
+
.transform_values! { _1[:default] }
|
40
|
+
|
41
|
+
init_method = Init.send(:define_initialize, pos_params, kw_params, opt_kw_params)
|
47
42
|
define_method :initialize, init_method
|
48
43
|
end
|
49
|
-
end
|
50
44
|
|
51
|
-
|
52
|
-
|
53
|
-
# @param [Hash[Symbol Boolean]] kw_attrs
|
54
|
-
private def define_initialize(attrs, kw_attrs)
|
55
|
-
->(*values, **kw_values) do
|
45
|
+
class << self
|
46
|
+
private def sanitize_attrs(attrs, **default_options)
|
56
47
|
|
57
|
-
|
58
|
-
raise ArgumentError, "wrong number of arguments (given #{values.size}, expected #{attrs.size})"
|
59
|
-
end
|
48
|
+
raise ArgumentError, 'At least 1 attribute is required.' if attrs.empty?
|
60
49
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
raise ArgumentError, "missing keywords: #{missing_keys}"
|
50
|
+
unless ::Trinkets::Class::Init::ATTR.include?(default_options[:attr])
|
51
|
+
attr = default_options[:attr].inspect
|
52
|
+
raise ArgumentError, "wrong `attr` type (given #{attr}, expected :accessor (default), :reader, :writer or :none)"
|
65
53
|
end
|
66
54
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
55
|
+
# Normalize attrs into an array: [[:name, **options], ...]
|
56
|
+
# @type [Array[Array[Symbol, Hash]]]
|
57
|
+
attrs = attrs.map do |a|
|
58
|
+
name, opts = [*a]
|
59
|
+
name = name.to_s.sub(/^@/, '').to_sym
|
60
|
+
opts = default_options.merge(opts || {})
|
61
|
+
[name, opts]
|
71
62
|
end
|
72
63
|
|
73
|
-
attrs.
|
74
|
-
|
75
|
-
|
64
|
+
repeated_attrs = attrs.map(&:first)
|
65
|
+
.tally
|
66
|
+
.select { |_, count| count > 1 }
|
67
|
+
.keys
|
76
68
|
|
77
|
-
|
78
|
-
instance_variable_set "@#{name}", value
|
79
|
-
end
|
69
|
+
raise ArgumentError, "duplicated argument names: #{repeated_attrs.join(', ')}" if repeated_attrs.any?
|
80
70
|
|
71
|
+
attrs.to_h
|
72
|
+
end
|
73
|
+
|
74
|
+
# @param [Array[Symbol]] pos_params
|
75
|
+
# @param [Array[Symbol]] kw_params
|
76
|
+
# @param [Hash[Symbol, Object]] opt_kw_params
|
77
|
+
private def define_initialize(pos_params, kw_params, opt_kw_params)
|
78
|
+
->(*values, **kw_values) do
|
79
|
+
|
80
|
+
unless pos_params.size == values.size
|
81
|
+
raise ArgumentError, "wrong number of arguments (given #{values.size}, expected #{pos_params.size})"
|
82
|
+
end
|
83
|
+
|
84
|
+
missing_keys = kw_params - kw_values.keys
|
85
|
+
unless missing_keys.empty?
|
86
|
+
missing_keys = missing_keys.map(&:inspect).join(', ')
|
87
|
+
raise ArgumentError, "missing keywords: #{missing_keys}"
|
88
|
+
end
|
89
|
+
|
90
|
+
unknown_keywords = kw_values.except(*kw_params, *opt_kw_params.keys)
|
91
|
+
unless unknown_keywords.empty?
|
92
|
+
unknown_keywords = unknown_keywords.keys.map(&:to_sym).map(&:inspect).join(', ')
|
93
|
+
raise ArgumentError, "unknown keywords: #{unknown_keywords}"
|
94
|
+
end
|
95
|
+
|
96
|
+
pos_params.zip(values).each do |name, value|
|
97
|
+
instance_variable_set "@#{name}", value
|
98
|
+
end
|
99
|
+
|
100
|
+
kw_params.each do |name|
|
101
|
+
instance_variable_set "@#{name}", kw_values[name]
|
102
|
+
end
|
103
|
+
|
104
|
+
opt_kw_params.each do |name, default_value|
|
105
|
+
value = kw_values.include?(name) ? kw_values[name] : default_value
|
106
|
+
instance_variable_set "@#{name}", value
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
81
110
|
end
|
82
111
|
end
|
83
112
|
end
|
84
|
-
|
85
113
|
end
|
86
114
|
end
|
data/lib/trinkets/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trinkets
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SilverPhoenix99
|
@@ -9,8 +9,36 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-02-
|
13
|
-
dependencies:
|
12
|
+
date: 2024-02-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '3.0'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '3.0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: simplecov
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.22.0
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 0.22.0
|
14
42
|
description: Truly outrageous bootleg facets in your trinkets box.
|
15
43
|
email:
|
16
44
|
- antoniopedrosilvapinto@gmail.com
|
@@ -37,7 +65,10 @@ homepage: https://github.com/SilverPhoenix99/trinkets
|
|
37
65
|
licenses:
|
38
66
|
- MIT
|
39
67
|
metadata:
|
40
|
-
|
68
|
+
source_code_uri: https://github.com/SilverPhoenix99/trinkets
|
69
|
+
changelog_uri: https://github.com/SilverPhoenix99/trinkets/blob/master/CHANGELOG.md
|
70
|
+
bug_tracker_uri: https://github.com/SilverPhoenix99/trinkets/issues
|
71
|
+
documentation_uri: https://github.com/SilverPhoenix99/trinkets/blob/master/README.md
|
41
72
|
post_install_message:
|
42
73
|
rdoc_options: []
|
43
74
|
require_paths:
|