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 +4 -4
- data/README.md +75 -4
- data/lib/smart_init/main.rb +19 -38
- data/lib/smart_init/version.rb +1 -1
- data/test/test_hash_public_accessors.rb +72 -0
- data/test/test_hash_public_mixed.rb +81 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a0d2189c40504fff065e0606ff59bb2c529ea2df100a5d835ae88ba1b89abea
|
4
|
+
data.tar.gz: 536894bb01f7dca209c6686bf0ac7e6960ca257069608e737731f01dd0c36a48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d54eea8c78672566034ac4401764942b760a1f39b3be1b69fec278537a2573ad027ccb19c74d1e2e3a2f5d4248b743eb8eff76d0f15ce6560245d06b924bf0fb
|
7
|
+
data.tar.gz: 65aa81859e5589a1ee31f6f0d7ec119ab46570b3aa6167bccac2355dad097e68be337fc6ee3f8afec58d2b4b385a34c0ebabe3977273ce5bd09b632e6979ea19
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Smart Init [](https://travis-ci.org/pawurb/smart_init) [](https://badge.fury.io/rb/smart_init)
|
2
2
|
|
3
|
-
Do you find yourself writing a lot of boilerplate code like
|
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
|
-
|
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 #<
|
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,
|
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
|
data/lib/smart_init/main.rb
CHANGED
@@ -11,41 +11,28 @@ module SmartInit
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
def initialize_with_hash
|
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
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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.
|
27
|
+
unless parameters.has_key?(required_attr)
|
40
28
|
raise ArgumentError, "missing required attribute #{required_attr}"
|
41
29
|
end
|
42
30
|
end
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
-
|
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 +
|
43
|
+
all_readers = (required_attrs + attributes_and_options.keys)
|
57
44
|
attr_reader(*all_readers)
|
58
|
-
|
59
|
-
|
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
|
|
data/lib/smart_init/version.rb
CHANGED
@@ -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.
|
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-
|
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
|