trinkets 0.3.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cb82b9c6f72cce48f7d303e989870bc05e77429508c17f266428d15bc0821628
4
- data.tar.gz: 1dc0a8334a869e8be5b4e397caeed6be9ff16b495514425e184938d538b0b2e1
3
+ metadata.gz: 1b95bff0eaa948f0edc0375709fd3ec786ad10e970f5b5abcd501247dceb1e74
4
+ data.tar.gz: 3d4d1bce01e034167209cad41d9bf4ad356d79ddf100cfc1968d16b9686a06f9
5
5
  SHA512:
6
- metadata.gz: 4b57aecbcc07de7c710804302accad6fe49d610c133fabf74040a0cca376129258dc064eb967c0ff50570d72b46d641160fda6485222d29f47f06117b57db55c
7
- data.tar.gz: 7714dbbd7e295d87d9f6c98aac8d6aade0d6a57d86e69368c039e8022824511f897f1a2d8f90f5f70b1fb598741b4bfbfdbb5308a164f40dc2fcb6da01491148
6
+ metadata.gz: 5b3a7cc743fae16ee12cfab9d9efc4236b31d69d8a570fe1bbf009cc3558be08d3cef3a38aa110403fb40dea019a3236adbf4a00c983c5f1f4e148a909bfb884
7
+ data.tar.gz: e94881a3dc54ca93be7ea759b0b6aff8607b9d91d7d1247d3ec2f59d265ecb2ea4c7f014754ca9a4a351ee6994eabb2fcae0e93fe0d14d27a46b01985370c3f6
data/CHANGELOG.md CHANGED
@@ -1,4 +1,7 @@
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
+
2
5
  ### [0.3.1](https://github.com/SilverPhoenix99/trinkets/tree/v0.3.1)
3
6
  * Fixed repeated arguments in `Class::init`.
4
7
 
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,13 +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
- raise ArgumentError, 'At least 1 attribute is required.' if attrs.empty?
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
- attrs = ::Trinkets::Class.send(:sanitize_attrs, attrs, default_attr_options)
9
+ attrs = Init.send(:sanitize_attrs, attrs, attr: attr, kw: kw)
15
10
 
11
+ # @type [Hash[Symbol, Method]]
16
12
  attr_methods = (ATTR - [:none])
17
13
  .each_with_object({}) do |name, h|
18
14
  h[name] = method("attr_#{name}")
@@ -21,77 +17,98 @@ module Trinkets
21
17
  # even though options like `kw` aren't used, they serve here to validate the `attrs` options
22
18
  attr_init = ->(name, attr: ATTR.first, kw: false) do
23
19
  unless ATTR.include?(attr)
24
- raise ArgumentError, "attr `#{name}`, option attr` must be one of :accessor (default), :reader, :writer or :none"
20
+ raise ArgumentError, "wrong `attr` type for `#{name.inspect}` (given #{attr.inspect}, expected :accessor (default), :reader, :writer or :none)"
25
21
  end
26
22
  attr_methods[attr].call(name) unless attr == :none
27
23
  end
28
24
 
29
25
  attrs.each { |name, opts| attr_init.call(name, **opts) }
30
26
 
31
- # 2 hashes: { :name => bool }
32
- kw_attrs, attrs = attrs
33
- .map { |name, opts| [name, opts[:kw]] }
34
- .partition { |_, kw_opt| kw_opt }
35
- .map(&:to_h)
36
-
37
- init_method = ::Trinkets::Class.send(:define_initialize, attrs, kw_attrs)
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)
38
42
  define_method :initialize, init_method
39
43
  end
40
- end
41
-
42
- class << self
43
- private def sanitize_attrs(attrs, default_attr_options)
44
- # Normalize attrs into an array: [[:name, **options], ...]
45
- # @type [Array[Array[Symbol, Hash]]]
46
- attrs = attrs.map do |a|
47
- name, opts = [*a]
48
- name = name.to_s.sub(/^@/, '').to_sym
49
- opts = default_attr_options.merge(opts || {})
50
- [name, opts]
51
- end
52
-
53
- repeated_attrs = attrs.map(&:first)
54
- .tally
55
- .select { |_, count| count > 1 }
56
- .keys
57
-
58
- raise ArgumentError, "duplicated argument names: #{repeated_attrs.join(', ')}" if repeated_attrs.any?
59
44
 
60
- attrs.to_h
61
- end
45
+ class << self
46
+ private def sanitize_attrs(attrs, **default_options)
62
47
 
63
- # @param [Hash[Symbol Boolean]] attrs
64
- # @param [Hash[Symbol Boolean]] kw_attrs
65
- private def define_initialize(attrs, kw_attrs)
66
- ->(*values, **kw_values) do
48
+ raise ArgumentError, 'At least 1 attribute is required.' if attrs.empty?
67
49
 
68
- unless attrs.size == values.size
69
- raise ArgumentError, "wrong number of arguments (given #{values.size}, expected #{attrs.size})"
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)"
70
53
  end
71
54
 
72
- missing_keys = kw_attrs.except(*kw_values.keys)
73
- unless missing_keys.empty?
74
- missing_keys = missing_keys.keys.map(&:inspect).join(', ')
75
- raise ArgumentError, "missing keywords: #{missing_keys}"
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]
76
62
  end
77
63
 
78
- unknown_keywords = kw_values.except(*kw_attrs.keys)
79
- unless unknown_keywords.empty?
80
- unknown_keywords = unknown_keywords.keys.map(&:to_sym).map(&:inspect).join(', ')
81
- raise ArgumentError, "unknown keywords: #{unknown_keywords}"
82
- end
64
+ repeated_attrs = attrs.map(&:first)
65
+ .tally
66
+ .select { |_, count| count > 1 }
67
+ .keys
83
68
 
84
- attrs.keys.zip(values).each do |name, value|
85
- instance_variable_set "@#{name}", value
86
- end
69
+ raise ArgumentError, "duplicated argument names: #{repeated_attrs.join(', ')}" if repeated_attrs.any?
87
70
 
88
- kw_values.each do |name, value|
89
- instance_variable_set "@#{name}", value
90
- end
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
91
108
 
109
+ end
92
110
  end
93
111
  end
94
112
  end
95
-
96
113
  end
97
114
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Trinkets
4
- VERSION = '0.3.1'
4
+ VERSION = '0.4.0'
5
5
  end
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.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SilverPhoenix99
@@ -65,7 +65,6 @@ homepage: https://github.com/SilverPhoenix99/trinkets
65
65
  licenses:
66
66
  - MIT
67
67
  metadata:
68
- homepage_uri: https://github.com/SilverPhoenix99/trinkets
69
68
  source_code_uri: https://github.com/SilverPhoenix99/trinkets
70
69
  changelog_uri: https://github.com/SilverPhoenix99/trinkets/blob/master/CHANGELOG.md
71
70
  bug_tracker_uri: https://github.com/SilverPhoenix99/trinkets/issues