smart_init 4.1.1 → 4.2.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: a2e9bc1d28d5b3b07938020072647cc8a68a79992f1f82b849ad0626c589a284
4
- data.tar.gz: cc813ca9b90f91f72c94d713fc661d2c7810d761d45734ceec2218f2f39e3dbb
3
+ metadata.gz: 7a0d2189c40504fff065e0606ff59bb2c529ea2df100a5d835ae88ba1b89abea
4
+ data.tar.gz: 536894bb01f7dca209c6686bf0ac7e6960ca257069608e737731f01dd0c36a48
5
5
  SHA512:
6
- metadata.gz: 9ff873c3e7fee704df155ebacb862a92c663c9c5613535a1c77d6fd91e07d3f086081abb22915d415ee5bc8774882e00af06d42a0bfa371f4a67fb2611cb9798
7
- data.tar.gz: 4b8e6651302c3b18b25caa8ce2cc392fdb65089f5d5c56c020af31b6e0e47d9b79090d1965b8d2248951678bed8c5a2e97562a708ba7f5fa67ea32f080aeb5de
6
+ metadata.gz: d54eea8c78672566034ac4401764942b760a1f39b3be1b69fec278537a2573ad027ccb19c74d1e2e3a2f5d4248b743eb8eff76d0f15ce6560245d06b924bf0fb
7
+ data.tar.gz: 65aa81859e5589a1ee31f6f0d7ec119ab46570b3aa6167bccac2355dad097e68be337fc6ee3f8afec58d2b4b385a34c0ebabe3977273ce5bd09b632e6979ea19
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Smart Init [![Build Status](https://travis-ci.org/pawurb/smart_init.svg)](https://travis-ci.org/pawurb/smart_init) [![Gem Version](https://badge.fury.io/rb/smart_init.svg)](https://badge.fury.io/rb/smart_init)
2
2
 
3
- Do you find yourself writing a lot of boilerplate code like that?
3
+ Do you find yourself writing a lot of boilerplate code like this?
4
4
 
5
5
  ```ruby
6
6
  def initialize(network_provider, api_token)
@@ -13,7 +13,7 @@ def self.call(network_provider, api_token)
13
13
  end
14
14
  ```
15
15
 
16
- Gem provides a simple DSL for getting rid of it. It offers an alternative to using `Struct.new` which does not check for number of parameters provided in initializer, exposes getters and instantiates unecessary class instances.
16
+ This gem provides a simple DSL for getting rid of it. It offers an alternative to using `Struct.new` which does not check for number of parameters provided in initializer, exposes getters and instantiates unecessary class instances.
17
17
 
18
18
  **Smart Init** offers a unified API convention for stateless service objects, accepting values in initializer and exposing one public class method `call` which instantiates new objects and accepts arguments passed to initializer.
19
19
 
@@ -141,12 +141,83 @@ end
141
141
 
142
142
  client = SemiPublicApiClient.new(network_provider: Faraday.new, api_token: 'secret_token')
143
143
  client.network_provider => #<Faraday::Connection:0x000...>
144
- client.api_token => 'secret_token' => # NoMethodError (private method `api_token' called for #<ApiClient:0x000...>)
144
+ client.api_token => 'secret_token' => # NoMethodError (private method `api_token' called for #<SemiPublicApiClient:0x000...>)
145
+ ```
146
+
147
+ ### Accessors access
148
+
149
+ Similarly, this is how it would look if you tried to use a writer method:
150
+
151
+ ```ruby
152
+ client = ApiClient.new(network_provider: Faraday.new, api_token: 'secret_token')
153
+ client.api_token = 'new_token' => # NoMethodError (private method `api_token=' called for #<ApiClient:0x000..>)
154
+ ```
155
+
156
+ Optionally you can make all or subset of accessors public using the `public_accessors` config option. It accepts `true` or an array of method names as an argument. This will provide both reader and writer methods publicly.
157
+
158
+ ```ruby
159
+ class PublicApiClient < SmartInit::Base
160
+ initialize_with :network_provider, :api_token, public_accessors: true
161
+ end
162
+
163
+ client = PublicApiClient.new(network_provider: Faraday.new, api_token: 'secret_token')
164
+ client.network_provider => #<Faraday::Connection:0x000...>
165
+ client.network_provider = Typhoeus::Request.new(...) => #<Typhoeus::Request:0x000...>
166
+ client.api_token => 'secret_token'
167
+ client.api_token = 'new_token' => 'new_token'
168
+ ```
169
+
170
+ ```ruby
171
+ class SemiPublicApiClient < SmartInit::Base
172
+ initialize_with :network_provider, :api_token, public_accessors: [:network_provider]
173
+ end
174
+
175
+ client = SemiPublicApiClient.new(network_provider: Faraday.new, api_token: 'secret_token')
176
+ client.network_provider => #<Faraday::Connection:0x000...>
177
+ client.network_provider = Typhoeus::Request.new(...) => #<Typhoeus::Request:0x000...>
178
+ client.api_token => # NoMethodError (private method `api_token' called for #<SemiPublicApiClient:0x000...>)
179
+ client.api_token = 'new_token' => # NoMethodError (undefined method `api_token=' called for #<SemiPublicApiClient:0x000...>)
180
+ ```
181
+
182
+ Finally, you can mix them together like this:
183
+
184
+ ```ruby
185
+ class PublicReadersSemiPublicAccessorsApiClient < SmartInit::Base
186
+ initialize_with :network_provider, :api_token, :timeout,
187
+ public_readers: true, public_accessors: [:network_provider]
188
+ end
189
+
190
+ client = PublicReadersSemiPublicAccessorsApiClient.new(
191
+ network_provider: Faraday.new, api_token: 'secret_token', timeout_length: 100
192
+ )
193
+ client.network_provider => #<Faraday::Connection:0x000...>
194
+ client.network_provider = Typhoeus::Request.new(...) => #<Typhoeus::Request:0x000...>
195
+ client.api_token => 'secret_token'
196
+ client.api_token = 'new_token' => # NoMethodError (undefined method `api_token=' called for #<SemiPublicApiClient:0x000...>)
197
+ client.timeout_length => 100
198
+ client.timeout_length = 150 => # NoMethodError (undefined method `timeout_length=' called for #<SemiPublicApiClient:0x000...>)
199
+ ```
200
+
201
+ ```ruby
202
+ class SemiPublicReadersSemiPublicAccessorsApiClient < SmartInit::Base
203
+ initialize_with :network_provider, :api_token, :timeout,
204
+ public_readers: [:timeout], public_accessors: [:network_provider]
205
+ end
206
+
207
+ client = SemiPublicReadersSemiPublicAccessorsApiClient.new(
208
+ network_provider: Faraday.new, api_token: 'secret_token', timeout_length: 100
209
+ )
210
+ client.network_provider => #<Faraday::Connection:0x000...>
211
+ client.network_provider = Typhoeus::Request.new(...) => #<Typhoeus::Request:0x000...>
212
+ client.api_token => # NoMethodError (private method `api_token' called for #<SemiPublicReadersSemiPublicAccessorsApiClient:0x000...>)
213
+ client.api_token = 'new_token' => # NoMethodError (undefined method `api_token=' called for #<SemiPublicReadersSemiPublicAccessorsApiClient:0x000...>)
214
+ client.timeout_length => 100
215
+ client.timeout_length = 150 => # NoMethodError (undefined method `timeout_length=' called for #<SemiPublicReadersSemiPublicAccessorsApiClient:0x000...>)
145
216
  ```
146
217
 
147
218
  ## Arguments API
148
219
 
149
- Alternatively you can use an API without hash arguments, default values and public readers support:
220
+ Alternatively you can use an API without hash arguments, default values, public readers, or public accessors support:
150
221
 
151
222
  ```ruby
152
223
  class Calculator < SmartInit::Base
@@ -11,41 +11,28 @@ module SmartInit
11
11
  end
12
12
  end
13
13
 
14
- def initialize_with_hash *attributes
15
- public_readers_filter = -> (el) {
16
- el.is_a?(Hash) && el.keys == [:public_readers]
17
- }
18
- attributes = attributes.map do |el|
19
- if el.is_a?(Hash)
20
- el.map { |k, v| { k => v } }
21
- else
22
- el
23
- end
24
- end.flatten
25
-
26
- public_readers = attributes.select(&public_readers_filter)
27
- attributes.delete_if(&public_readers_filter)
28
- required_attrs = attributes.select { |el| el.is_a?(Symbol) }
29
-
30
- default_value_attrs = attributes.select { |el| el.is_a?(Hash) }.reduce(Hash.new, :merge) || {}
14
+ def initialize_with_hash(*required_attrs, **attributes_and_options)
31
15
 
32
- define_method :initialize do |*parameters|
33
- parameters = [{}] if parameters == []
34
- unless parameters.first.is_a?(Hash)
35
- raise ArgumentError, "invalid input, expected hash of attributes"
36
- end
16
+ public_readers = attributes_and_options.delete(:public_readers) || []
17
+ public_accessors = attributes_and_options.delete(:public_accessors) || []
18
+ if public_readers == true || public_accessors == true
19
+ public_readers = required_attrs
20
+ public_accessors = required_attrs if public_accessors == true
21
+ else
22
+ public_readers += public_accessors
23
+ end
37
24
 
25
+ define_method :initialize do |**parameters|
38
26
  required_attrs.each do |required_attr|
39
- unless parameters.first.has_key?(required_attr)
27
+ unless parameters.has_key?(required_attr)
40
28
  raise ArgumentError, "missing required attribute #{required_attr}"
41
29
  end
42
30
  end
43
-
44
- (required_attrs + default_value_attrs.keys).each do |attribute|
45
- value = if parameters.first.has_key?(attribute)
46
- parameters.first.fetch(attribute)
31
+ (required_attrs + attributes_and_options.keys).each do |attribute|
32
+ value = if parameters.has_key?(attribute)
33
+ parameters.fetch(attribute)
47
34
  else
48
- default_value_attrs[attribute]
35
+ attributes_and_options[attribute]
49
36
  end
50
37
 
51
38
  instance_variable_set("@#{attribute}", value)
@@ -53,18 +40,12 @@ module SmartInit
53
40
  end
54
41
 
55
42
  instance_eval do
56
- all_readers = (required_attrs + default_value_attrs.keys).compact
43
+ all_readers = (required_attrs + attributes_and_options.keys)
57
44
  attr_reader(*all_readers)
58
-
59
- if public_readers.count == 0
60
- all_readers.each do |method_name|
61
- private method_name
62
- end
63
- elsif public_readers.first.fetch(:public_readers).is_a?(Array)
64
- (all_readers - public_readers.first.fetch(:public_readers)).each do |method_name|
65
- private method_name
66
- end
45
+ (all_readers - public_readers).each do |reader|
46
+ private reader
67
47
  end
48
+ attr_writer(*public_accessors)
68
49
  end
69
50
  end
70
51
 
@@ -1,3 +1,3 @@
1
1
  module SmartInit
2
- VERSION = "4.1.1"
2
+ VERSION = "4.2.0"
3
3
  end
@@ -0,0 +1,72 @@
1
+ require "byebug"
2
+ require "test/unit"
3
+ require_relative '../lib/smart_init/main'
4
+
5
+ class TestAllPublic
6
+ extend SmartInit
7
+ initialize_with :attribute_1, :attribute_2, public_accessors: true
8
+ is_callable
9
+
10
+ def call
11
+ [attribute_1, attribute_2]
12
+ end
13
+ end
14
+
15
+ class TestSomePublic
16
+ extend SmartInit
17
+ initialize_with :attribute_1, :attribute_2, public_accessors: [:attribute_1]
18
+ is_callable
19
+
20
+ def call
21
+ [attribute_1, attribute_2]
22
+ end
23
+ end
24
+
25
+ class TestDefaultPublic
26
+ extend SmartInit
27
+ initialize_with :attribute_1, attribute_2: 2, public_accessors: [:attribute_2]
28
+
29
+ def call
30
+ [attribute_1, attribute_2]
31
+ end
32
+ end
33
+
34
+ class HashApiPublicTest < Test::Unit::TestCase
35
+ def test_all_public
36
+ service = TestAllPublic.new(attribute_1: "a", attribute_2: "b")
37
+ assert_nothing_raised do
38
+ service.attribute_1 = "c"
39
+ service.attribute_2 = "d"
40
+ end
41
+ assert_equal service.attribute_1, "c"
42
+ assert_equal service.attribute_2, "d"
43
+ end
44
+
45
+ def test_some_public
46
+ service = TestSomePublic.new(attribute_1: "a", attribute_2: "b")
47
+ assert_nothing_raised do
48
+ service.attribute_1 = "c"
49
+ end
50
+ assert_equal service.attribute_1, "c"
51
+ assert_raise NoMethodError do
52
+ service.attribute_2
53
+ end
54
+ assert_raise NoMethodError do
55
+ service.attribute_2 = "d"
56
+ end
57
+ end
58
+
59
+ def test_default_public
60
+ service = TestDefaultPublic.new(attribute_1: "a")
61
+ assert_nothing_raised do
62
+ service.attribute_2 = 3
63
+ end
64
+ assert_equal service.attribute_2, 3
65
+ assert_raise NoMethodError do
66
+ service.attribute_1 = "b"
67
+ end
68
+ assert_raise NoMethodError do
69
+ service.attribute_1
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,81 @@
1
+ require "byebug"
2
+ require "test/unit"
3
+ require_relative '../lib/smart_init/main'
4
+
5
+ class TestSomePublicMixed
6
+ extend SmartInit
7
+ initialize_with :attribute_1, :attribute_2, :attribute_3, :attribute_4,
8
+ public_readers: [:attribute_1],
9
+ public_accessors: [:attribute_2, :attribute_3]
10
+ is_callable
11
+
12
+ def call
13
+ [attribute_1, attribute_2, attribute_3, attribute_4]
14
+ end
15
+ end
16
+
17
+ class TestAllReadersSomeAccessorsPublic
18
+ extend SmartInit
19
+ initialize_with :attribute_1, :attribute_2, public_readers: true, public_accessors: [:attribute_2]
20
+
21
+ def call
22
+ [attribute_1, attribute_2]
23
+ end
24
+ end
25
+
26
+ class HashApiPublicTest < Test::Unit::TestCase
27
+
28
+ def test_readers_some_public_mixed
29
+ service = TestSomePublicMixed.new(
30
+ attribute_1: "a", attribute_2: "b",
31
+ attribute_3: "c", attribute_4: "d"
32
+ )
33
+ assert_nothing_raised do
34
+ service.attribute_1
35
+ service.attribute_2
36
+ service.attribute_3
37
+ end
38
+ assert_raise NoMethodError do
39
+ service.attribute_4
40
+ end
41
+ end
42
+
43
+ def test_writers_some_public_mixed
44
+ service = TestSomePublicMixed.new(
45
+ attribute_1: "a", attribute_2: "b",
46
+ attribute_3: "c", attribute_4: "d"
47
+ )
48
+ assert_nothing_raised do
49
+ service.attribute_2 = "e"
50
+ service.attribute_3 = "f"
51
+ end
52
+ assert_equal service.attribute_2, "e"
53
+ assert_equal service.attribute_3, "f"
54
+ assert_raise NoMethodError do
55
+ service.attribute_4 = "g"
56
+ end
57
+ end
58
+
59
+ def test_readers_all_readers_some_accessors_public
60
+ service = TestAllReadersSomeAccessorsPublic.new(
61
+ attribute_1: "a", attribute_2: "b"
62
+ )
63
+ assert_nothing_raised do
64
+ service.attribute_1
65
+ service.attribute_2
66
+ end
67
+ end
68
+
69
+ def test_writers_all_readers_some_accessors_public
70
+ service = TestAllReadersSomeAccessorsPublic.new(
71
+ attribute_1: "a", attribute_2: "b"
72
+ )
73
+ assert_raise NoMethodError do
74
+ service.attribute_1 = "c"
75
+ end
76
+ assert_nothing_raised do
77
+ service.attribute_2 = "d"
78
+ end
79
+ assert_equal service.attribute_2, "d"
80
+ end
81
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_init
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.1
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - pawurb
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-25 00:00:00.000000000 Z
11
+ date: 2020-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -71,6 +71,8 @@ files:
71
71
  - smart_init.gemspec
72
72
  - test/test_args_api.rb
73
73
  - test/test_hash_api.rb
74
+ - test/test_hash_public_accessors.rb
75
+ - test/test_hash_public_mixed.rb
74
76
  - test/test_hash_public_readers.rb
75
77
  homepage: http://github.com/pawurb/smart_init
76
78
  licenses:
@@ -98,4 +100,6 @@ summary: Remove Ruby initializer boilerplate code
98
100
  test_files:
99
101
  - test/test_args_api.rb
100
102
  - test/test_hash_api.rb
103
+ - test/test_hash_public_accessors.rb
104
+ - test/test_hash_public_mixed.rb
101
105
  - test/test_hash_public_readers.rb