smart_init 4.1.1 → 4.2.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: 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