trinkets 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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