sinclair 1.10.0 → 1.11.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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/README.md +414 -324
  4. data/config/check_specs.yml +3 -4
  5. data/config/yardstick.yml +2 -0
  6. data/lib/sinclair/matchers/add_class_method.rb +0 -1
  7. data/lib/sinclair/method_builder/base.rb +17 -2
  8. data/lib/sinclair/method_builder/call_method_builder.rb +21 -21
  9. data/lib/sinclair/method_builder.rb +5 -20
  10. data/lib/sinclair/method_definition/block_definition.rb +2 -0
  11. data/lib/sinclair/method_definition/call_definition.rb +15 -18
  12. data/lib/sinclair/method_definition/string_definition.rb +2 -0
  13. data/lib/sinclair/method_definition.rb +41 -3
  14. data/lib/sinclair/method_definitions.rb +20 -22
  15. data/lib/sinclair/version.rb +1 -1
  16. data/lib/sinclair.rb +149 -62
  17. data/spec/integration/readme/sinclair/types_of_definition_spec.rb +47 -0
  18. data/spec/integration/yard/sinclair/add_class_method_spec.rb +51 -0
  19. data/spec/integration/yard/sinclair/add_method_spec.rb +60 -0
  20. data/spec/integration/yard/sinclair/eval_and_add_method_spec.rb +26 -0
  21. data/spec/integration/yard/sinclair_spec.rb +0 -83
  22. data/spec/lib/sinclair/method_builder/base_spec.rb +15 -0
  23. data/spec/lib/sinclair/method_definition/call_definition_spec.rb +14 -17
  24. data/spec/lib/sinclair/method_definition_spec.rb +67 -2
  25. data/spec/lib/sinclair/method_definitions_spec.rb +15 -16
  26. data/spec/lib/sinclair_spec.rb +6 -160
  27. data/spec/support/models/dummy_builder.rb +4 -1
  28. data/spec/support/models/dummy_class_builder.rb +3 -0
  29. data/spec/support/models/person.rb +1 -1
  30. data/spec/support/shared_examples/sinclair.rb +112 -0
  31. metadata +8 -2
data/README.md CHANGED
@@ -13,22 +13,24 @@ This gem helps the creation of complex gems/concerns
13
13
  that enables creation of methods on the fly through class
14
14
  methods
15
15
 
16
- Next release: [1.11.0](https://github.com/darthjee/sinclair/compare/1.10.0...master)
16
+ Current Release: [1.11.0](https://github.com/darthjee/sinclair/tree/1.11.0)
17
+
18
+ [Next release](https://github.com/darthjee/sinclair/compare/1.11.0...master)
17
19
 
18
20
  Yard Documentation
19
21
  -------------------
20
- [https://www.rubydoc.info/gems/sinclair/1.10.0](https://www.rubydoc.info/gems/sinclair/1.10.0)
22
+ [https://www.rubydoc.info/gems/sinclair/1.11.0](https://www.rubydoc.info/gems/sinclair/1.11.0)
21
23
 
22
24
  Installation
23
25
  ---------------
24
26
 
25
- - Install it
27
+ - Install it
26
28
 
27
29
  ```ruby
28
30
  gem install sinclair
29
31
  ```
30
32
 
31
- - Or add Sinclair to your `Gemfile` and `bundle install`:
33
+ - Or add Sinclair to your `Gemfile` and `bundle install`:
32
34
 
33
35
  ```ruby
34
36
  gem 'sinclair'
@@ -41,193 +43,202 @@ Installation
41
43
  Usage
42
44
  ---------------
43
45
  ### Sinclair builder
44
- Sinclair can actually be used in several ways, as a stand alone object capable of
45
- adding methods to your class on the fly, as a builder inside a class method
46
- or by extending it for more complex logics
46
+ Sinclair can actually be used in several ways
47
+ - as a stand alone object capable of adding methods to your class on the fly
48
+ - as a builder inside a class method
49
+ - extending the builder for more complex logics
47
50
 
48
- #### Stand Alone usage creating methods on the fly
49
- ```ruby
51
+ <details>
52
+ <summary>Stand Alone usage creating methods on the fly</summary>
50
53
 
51
- class Clazz
52
- end
54
+ ```ruby
55
+ class Clazz
56
+ end
53
57
 
54
- builder = Sinclair.new(Clazz)
58
+ builder = Sinclair.new(Clazz)
55
59
 
56
- builder.add_method(:twenty, '10 + 10')
57
- builder.add_method(:eighty) { 4 * twenty }
58
- builder.add_class_method(:one_hundred) { 100 }
59
- builder.add_class_method(:one_hundred_twenty, 'one_hundred + 20')
60
- builder.build
60
+ builder.add_method(:twenty, '10 + 10')
61
+ builder.add_method(:eighty) { 4 * twenty }
62
+ builder.add_class_method(:one_hundred) { 100 }
63
+ builder.add_class_method(:one_hundred_twenty, 'one_hundred + 20')
64
+ builder.build
61
65
 
62
- instance = Clazz.new
66
+ instance = Clazz.new
63
67
 
64
- puts "Twenty => #{instance.twenty}" # Twenty => 20
65
- puts "Eighty => #{instance.eighty}" # Eighty => 80
68
+ puts "Twenty => #{instance.twenty}" # Twenty => 20
69
+ puts "Eighty => #{instance.eighty}" # Eighty => 80
66
70
 
67
- puts "One Hundred => #{Clazz.one_hundred}" # One Hundred => 100
68
- puts "One Hundred => #{Clazz.one_hundred_twenty}" # One Hundred Twenty => 120
71
+ puts "One Hundred => #{Clazz.one_hundred}" # One Hundred => 100
72
+ puts "One Hundred => #{Clazz.one_hundred_twenty}" # One Hundred Twenty => 120
69
73
  ```
74
+ </details>
70
75
 
71
- #### Builder in class method
76
+ <details>
77
+ <summary>Builder in class method</summary>
72
78
 
73
79
  ```ruby
74
- class HttpJsonModel
75
- attr_reader :json
76
-
77
- class << self
78
- def parse(attribute, path: [])
79
- builder = Sinclair.new(self)
80
+ class HttpJsonModel
81
+ attr_reader :json
80
82
 
81
- keys = (path + [attribute]).map(&:to_s)
83
+ class << self
84
+ def parse(attribute, path: [])
85
+ builder = Sinclair.new(self)
82
86
 
83
- builder.add_method(attribute) do
84
- keys.inject(hash) { |h, key| h[key] }
85
- end
87
+ keys = (path + [attribute]).map(&:to_s)
86
88
 
87
- builder.build
89
+ builder.add_method(attribute) do
90
+ keys.inject(hash) { |h, key| h[key] }
88
91
  end
89
- end
90
-
91
- def initialize(json)
92
- @json = json
93
- end
94
92
 
95
- def hash
96
- @hash ||= JSON.parse(json)
93
+ builder.build
97
94
  end
98
95
  end
99
96
 
100
- class HttpPerson < HttpJsonModel
101
- parse :uid
102
- parse :name, path: [:personal_information]
103
- parse :age, path: [:personal_information]
104
- parse :username, path: [:digital_information]
105
- parse :email, path: [:digital_information]
97
+ def initialize(json)
98
+ @json = json
106
99
  end
107
100
 
108
- json = <<-JSON
109
- {
110
- "uid": "12sof511",
111
- "personal_information":{
112
- "name":"Bob",
113
- "age": 21
114
- },
115
- "digital_information":{
116
- "username":"lordbob",
117
- "email":"lord@bob.com"
118
- }
101
+ def hash
102
+ @hash ||= JSON.parse(json)
103
+ end
104
+ end
105
+
106
+ class HttpPerson < HttpJsonModel
107
+ parse :uid
108
+ parse :name, path: [:personal_information]
109
+ parse :age, path: [:personal_information]
110
+ parse :username, path: [:digital_information]
111
+ parse :email, path: [:digital_information]
112
+ end
113
+
114
+ json = <<-JSON
115
+ {
116
+ "uid": "12sof511",
117
+ "personal_information":{
118
+ "name":"Bob",
119
+ "age": 21
120
+ },
121
+ "digital_information":{
122
+ "username":"lordbob",
123
+ "email":"lord@bob.com"
119
124
  }
120
- JSON
125
+ }
126
+ JSON
121
127
 
122
- person = HttpPerson.new(json)
128
+ person = HttpPerson.new(json)
123
129
 
124
- person.uid # returns '12sof511'
125
- person.name # returns 'Bob'
126
- person.age # returns 21
127
- person.username # returns 'lordbob'
128
- person.email # returns 'lord@bob.com'
130
+ person.uid # returns '12sof511'
131
+ person.name # returns 'Bob'
132
+ person.age # returns 21
133
+ person.username # returns 'lordbob'
134
+ person.email # returns 'lord@bob.com'
129
135
  ```
136
+ </details>
130
137
 
131
- ```ruby
132
- module EnvSettings
133
- def env_prefix(new_prefix=nil)
134
- @env_prefix = new_prefix if new_prefix
135
- @env_prefix
136
- end
138
+ <details>
139
+ <summary>Class method adding class methods</summary>
137
140
 
138
- def from_env(*method_names)
139
- builder = Sinclair.new(self)
141
+ ```ruby
142
+ module EnvSettings
143
+ def env_prefix(new_prefix=nil)
144
+ @env_prefix = new_prefix if new_prefix
145
+ @env_prefix
146
+ end
140
147
 
141
- method_names.each do |method_name|
142
- env_key = [env_prefix, method_name].compact.join('_').upcase
148
+ def from_env(*method_names)
149
+ builder = Sinclair.new(self)
143
150
 
144
- builder.add_class_method(method_name, cached: true) do
145
- ENV[env_key]
146
- end
151
+ method_names.each do |method_name|
152
+ env_key = [env_prefix, method_name].compact.join('_').upcase
147
153
 
148
- builder.build
154
+ builder.add_class_method(method_name, cached: true) do
155
+ ENV[env_key]
149
156
  end
157
+
158
+ builder.build
150
159
  end
151
160
  end
161
+ end
152
162
 
153
- class MyServerConfig
154
- extend EnvSettings
163
+ class MyServerConfig
164
+ extend EnvSettings
155
165
 
156
- env_prefix :server
166
+ env_prefix :server
157
167
 
158
- from_env :host, :port
159
- end
168
+ from_env :host, :port
169
+ end
160
170
 
161
- ENV['SERVER_HOST'] = 'myserver.com'
162
- ENV['SERVER_PORT'] = '9090'
171
+ ENV['SERVER_HOST'] = 'myserver.com'
172
+ ENV['SERVER_PORT'] = '9090'
163
173
 
164
- MyServerConfig.host # returns 'myserver.com'
165
- MyServerConfig.port # returns '9090'
174
+ MyServerConfig.host # returns 'myserver.com'
175
+ MyServerConfig.port # returns '9090'
166
176
  ```
177
+ </details>
167
178
 
168
- #### Extending the builder
179
+ <details>
180
+ <summary>Extending the builder</summary>
169
181
 
170
182
  ```ruby
183
+ class ValidationBuilder < Sinclair
184
+ delegate :expected, to: :options_object
171
185
 
172
- class ValidationBuilder < Sinclair
173
- delegate :expected, to: :options_object
174
-
175
- def initialize(klass, options={})
176
- super
177
- end
178
-
179
- def add_validation(field)
180
- add_method("#{field}_valid?", "#{field}.is_a?#{expected}")
181
- end
186
+ def initialize(klass, options={})
187
+ super
188
+ end
182
189
 
183
- def add_accessors(fields)
184
- klass.send(:attr_accessor, *fields)
185
- end
190
+ def add_validation(field)
191
+ add_method("#{field}_valid?", "#{field}.is_a?#{expected}")
186
192
  end
187
193
 
188
- module MyConcern
189
- extend ActiveSupport::Concern
194
+ def add_accessors(fields)
195
+ klass.send(:attr_accessor, *fields)
196
+ end
197
+ end
190
198
 
191
- class_methods do
192
- def validate(*fields, expected_class)
193
- builder = ::ValidationBuilder.new(self, expected: expected_class)
199
+ module MyConcern
200
+ extend ActiveSupport::Concern
194
201
 
195
- validatable_fields.concat(fields)
196
- builder.add_accessors(fields)
202
+ class_methods do
203
+ def validate(*fields, expected_class)
204
+ builder = ::ValidationBuilder.new(self, expected: expected_class)
197
205
 
198
- fields.each do |field|
199
- builder.add_validation(field)
200
- end
206
+ validatable_fields.concat(fields)
207
+ builder.add_accessors(fields)
201
208
 
202
- builder.build
209
+ fields.each do |field|
210
+ builder.add_validation(field)
203
211
  end
204
212
 
205
- def validatable_fields
206
- @validatable_fields ||= []
207
- end
213
+ builder.build
208
214
  end
209
215
 
210
- def valid?
211
- self.class.validatable_fields.all? do |field|
212
- public_send("#{field}_valid?")
213
- end
216
+ def validatable_fields
217
+ @validatable_fields ||= []
214
218
  end
215
219
  end
216
220
 
217
- class MyClass
218
- include MyConcern
219
- validate :name, :surname, String
220
- validate :age, :legs, Integer
221
-
222
- def initialize(name: nil, surname: nil, age: nil, legs: nil)
223
- @name = name
224
- @surname = surname
225
- @age = age
226
- @legs = legs
221
+ def valid?
222
+ self.class.validatable_fields.all? do |field|
223
+ public_send("#{field}_valid?")
227
224
  end
228
225
  end
226
+ end
227
+
228
+ class MyClass
229
+ include MyConcern
230
+ validate :name, :surname, String
231
+ validate :age, :legs, Integer
232
+
233
+ def initialize(name: nil, surname: nil, age: nil, legs: nil)
234
+ @name = name
235
+ @surname = surname
236
+ @age = age
237
+ @legs = legs
238
+ end
239
+ end
229
240
 
230
- instance = MyClass.new
241
+ instance = MyClass.new
231
242
  ```
232
243
 
233
244
  the instance will respond to the methods
@@ -238,25 +249,73 @@ or by extending it for more complex logics
238
249
  ```valid?```.
239
250
 
240
251
  ```ruby
241
- valid_object = MyClass.new(
242
- name: :name,
243
- surname: 'surname',
244
- age: 20,
245
- legs: 2
246
- )
247
- valid_object.valid? # returns true
252
+ valid_object = MyClass.new(
253
+ name: :name,
254
+ surname: 'surname',
255
+ age: 20,
256
+ legs: 2
257
+ )
258
+ valid_object.valid? # returns true
259
+ ```
260
+
261
+ ```ruby
262
+ invalid_object = MyClass.new(
263
+ name: 'name',
264
+ surname: 'surname',
265
+ age: 20,
266
+ legs: 2
267
+ )
268
+ invalid_object.valid? # returns false
248
269
  ```
270
+ </details>
271
+
272
+ #### Different ways of adding the methods
273
+ There are different ways to add a method
274
+ <details>
275
+ <summary>Define method using block</summary>
249
276
 
250
277
  ```ruby
278
+ klass = Class.new
279
+ instance = klass.new
251
280
 
252
- invalid_object = MyClass.new(
253
- name: 'name',
254
- surname: 'surname',
255
- age: 20,
256
- legs: 2
257
- )
258
- invalid_object.valid? # returns false
281
+ builder = Sinclair.new(klass)
282
+ builder.add_method(:random_number) { Random.rand(10..20) }
283
+ builder.build
284
+
285
+ instance.random_number # returns a number between 10 and 20
286
+ ```
287
+ </details>
288
+
289
+ <details>
290
+ <summary>Define method using string</summary>
291
+
292
+ ```ruby
293
+ klass = Class.new
294
+ instance = klass.new
295
+
296
+ builder = Sinclair.new(klass)
297
+ builder.add_method(:random_number, "Random.rand(10..20)")
298
+ builder.build
299
+
300
+ instance.random_number # returns a number between 10 and 20
301
+ ```
302
+ </details>
303
+
304
+ <details>
305
+ <summary>Define method using a call to the class</summary>
306
+
307
+ ```ruby
308
+ klass = Class.new
309
+
310
+ builder = Sinclair.new(klass)
311
+ builder.add_class_method(:attr_accessor, :number, type: :call)
312
+ builder.build
313
+
314
+ klass.number # returns nil
315
+ klass.number = 10
316
+ klass.number # returns 10
259
317
  ```
318
+ </details>
260
319
 
261
320
  #### Caching the result
262
321
  If wanted, the result of the method can be stored in an
@@ -265,87 +324,95 @@ instance variable with the same name.
265
324
  When caching, you can cache with type `:full` so that even `nil`
266
325
  values are cached
267
326
 
327
+ <details>
328
+ <summary>Example of simple cache usage</summary>
329
+
268
330
  ```ruby
269
- class MyModel
270
- attr_accessor :base, :expoent
271
- end
331
+ class MyModel
332
+ attr_accessor :base, :expoent
333
+ end
272
334
 
273
- builder = Sinclair.new(MyModel)
335
+ builder = Sinclair.new(MyModel)
274
336
 
275
- builder.add_method(:cached_power, cached: true) do
276
- base ** expoent
277
- end
337
+ builder.add_method(:cached_power, cached: true) do
338
+ base ** expoent
339
+ end
278
340
 
279
- # equivalent of builder.add_method(:cached_power) do
280
- # @cached_power ||= base ** expoent
281
- # end
341
+ # equivalent of builder.add_method(:cached_power) do
342
+ # @cached_power ||= base ** expoent
343
+ # end
282
344
 
283
- builder.build
345
+ builder.build
284
346
 
285
- model.base = 3
286
- model.expoent = 2
347
+ model.base = 3
348
+ model.expoent = 2
287
349
 
288
- model.cached_power # returns 9
289
- model.expoent = 3
290
- model.cached_power # returns 9 (from cache)
350
+ model.cached_power # returns 9
351
+ model.expoent = 3
352
+ model.cached_power # returns 9 (from cache)
291
353
  ```
354
+ </details>
355
+
356
+ <details>
357
+ <summary>Usage of different cache types</summary>
292
358
 
293
359
  ```ruby
294
- module DefaultValueable
295
- def default_reader(*methods, value:, accept_nil: false)
296
- DefaultValueBuilder.new(
297
- self, value: value, accept_nil: accept_nil
298
- ).add_default_values(*methods)
299
- end
360
+ module DefaultValueable
361
+ def default_reader(*methods, value:, accept_nil: false)
362
+ DefaultValueBuilder.new(
363
+ self, value: value, accept_nil: accept_nil
364
+ ).add_default_values(*methods)
300
365
  end
366
+ end
301
367
 
302
- class DefaultValueBuilder < Sinclair
303
- def add_default_values(*methods)
304
- default_value = value
305
-
306
- methods.each do |method|
307
- add_method(method, cached: cache_type) { default_value }
308
- end
368
+ class DefaultValueBuilder < Sinclair
369
+ def add_default_values(*methods)
370
+ default_value = value
309
371
 
310
- build
372
+ methods.each do |method|
373
+ add_method(method, cached: cache_type) { default_value }
311
374
  end
312
375
 
313
- private
376
+ build
377
+ end
314
378
 
315
- delegate :accept_nil, :value, to: :options_object
379
+ private
316
380
 
317
- def cache_type
318
- accept_nil ? :full : :simple
319
- end
381
+ delegate :accept_nil, :value, to: :options_object
382
+
383
+ def cache_type
384
+ accept_nil ? :full : :simple
320
385
  end
386
+ end
321
387
 
322
- class Server
323
- extend DefaultValueable
388
+ class Server
389
+ extend DefaultValueable
324
390
 
325
- attr_writer :host, :port
391
+ attr_writer :host, :port
326
392
 
327
- default_reader :host, value: 'server.com', accept_nil: false
328
- default_reader :port, value: 80, accept_nil: true
393
+ default_reader :host, value: 'server.com', accept_nil: false
394
+ default_reader :port, value: 80, accept_nil: true
329
395
 
330
- def url
331
- return "http://#{host}" unless port
396
+ def url
397
+ return "http://#{host}" unless port
332
398
 
333
- "http://#{host}:#{port}"
334
- end
399
+ "http://#{host}:#{port}"
335
400
  end
401
+ end
336
402
 
337
- server = Server.new
403
+ server = Server.new
338
404
 
339
- server.url # returns 'http://server.com:80'
405
+ server.url # returns 'http://server.com:80'
340
406
 
341
- server.host = 'interstella.com'
342
- server.port = 5555
343
- server.url # returns 'http://interstella.com:5555'
407
+ server.host = 'interstella.com'
408
+ server.port = 5555
409
+ server.url # returns 'http://interstella.com:5555'
344
410
 
345
- server.host = nil
346
- server.port = nil
347
- server.url # return 'http://server.com'
411
+ server.host = nil
412
+ server.port = nil
413
+ server.url # return 'http://server.com'
348
414
  ```
415
+ </details>
349
416
 
350
417
  ### Sinclair::Configurable
351
418
 
@@ -356,214 +423,236 @@ Configurations are read-only objects that can only be set using
356
423
  the `configurable#configure` method which accepts a block or
357
424
  hash
358
425
 
426
+ <details>
427
+ <summary>Using configurable</summary>
428
+
359
429
  ```ruby
360
- module MyConfigurable
361
- extend Sinclair::Configurable
430
+ module MyConfigurable
431
+ extend Sinclair::Configurable
362
432
 
363
- # port is defaulted to 80
364
- configurable_with :host, port: 80
365
- end
433
+ # port is defaulted to 80
434
+ configurable_with :host, port: 80
435
+ end
366
436
 
367
- MyConfigurable.configure(port: 5555) do |config|
368
- config.host 'interstella.art'
369
- end
437
+ MyConfigurable.configure(port: 5555) do |config|
438
+ config.host 'interstella.art'
439
+ end
370
440
 
371
- MyConfigurable.config.host # returns 'interstella.art'
372
- MyConfigurable.config.port # returns 5555
441
+ MyConfigurable.config.host # returns 'interstella.art'
442
+ MyConfigurable.config.port # returns 5555
373
443
 
374
- # Configurable enables options that can be passed
375
- MyConfigurable.as_options.host # returns 'interstella.art'
444
+ # Configurable enables options that can be passed
445
+ MyConfigurable.as_options.host # returns 'interstella.art'
376
446
 
377
- # Configurable enables options that can be passed with custom values
378
- MyConfigurable.as_options(host: 'other').host # returns 'other'
447
+ # Configurable enables options that can be passed with custom values
448
+ MyConfigurable.as_options(host: 'other').host # returns 'other'
379
449
 
380
- MyConfigurable.reset_config
450
+ MyConfigurable.reset_config
381
451
 
382
- MyConfigurable.config.host # returns nil
383
- MyConfigurable.config.port # returns 80
452
+ MyConfigurable.config.host # returns nil
453
+ MyConfigurable.config.port # returns 80
384
454
  ```
455
+ </details>
385
456
 
386
457
  Configurations can also be done through custom classes
387
458
 
388
- ```ruby
389
- class MyServerConfig < Sinclair::Config
390
- config_attributes :host, :port
459
+ <details>
460
+ <summary>Using configration class</summary>
391
461
 
392
- def url
393
- if @port
394
- "http://#{@host}:#{@port}"
395
- else
396
- "http://#{@host}"
397
- end
462
+ ```ruby
463
+ class MyServerConfig < Sinclair::Config
464
+ config_attributes :host, :port
465
+
466
+ def url
467
+ if @port
468
+ "http://#{@host}:#{@port}"
469
+ else
470
+ "http://#{@host}"
398
471
  end
399
472
  end
473
+ end
400
474
 
401
- class Client
402
- extend Sinclair::Configurable
475
+ class Client
476
+ extend Sinclair::Configurable
403
477
 
404
- configurable_by MyServerConfig
405
- end
478
+ configurable_by MyServerConfig
479
+ end
406
480
 
407
- Client.configure do
408
- host 'interstella.com'
409
- end
481
+ Client.configure do
482
+ host 'interstella.com'
483
+ end
410
484
 
411
- Client.config.url # returns 'http://interstella.com'
485
+ Client.config.url # returns 'http://interstella.com'
412
486
 
413
- Client.configure do |config|
414
- config.port 8080
415
- end
487
+ Client.configure do |config|
488
+ config.port 8080
489
+ end
416
490
 
417
- Client.config.url # returns 'http://interstella.com:8080'
491
+ Client.config.url # returns 'http://interstella.com:8080'
418
492
  ```
493
+ </details>
419
494
 
420
495
  ### Sinclair::EnvSettable
421
496
 
422
497
  Settable allows classes to extract configuration from environments through
423
498
  a simple meta-programable way
424
499
 
500
+ <details>
501
+ <summary>Using env settable example</summary>
502
+
425
503
  ```ruby
426
- class ServiceClient
427
- extend Sinclair::EnvSettable
428
- attr_reader :username, :password, :host, :port
504
+ class ServiceClient
505
+ extend Sinclair::EnvSettable
506
+ attr_reader :username, :password, :host, :port
429
507
 
430
- settings_prefix 'SERVICE'
508
+ settings_prefix 'SERVICE'
431
509
 
432
- with_settings :username, :password, port: 80, hostname: 'my-host.com'
510
+ with_settings :username, :password, port: 80, hostname: 'my-host.com'
433
511
 
434
- def self.default
435
- @default ||= new
436
- end
512
+ def self.default
513
+ @default ||= new
514
+ end
437
515
 
438
- def initialize(
439
- username: self.class.username,
440
- password: self.class.password,
441
- port: self.class.port,
442
- hostname: self.class.hostname
443
- )
444
- @username = username
445
- @password = password
446
- @port = port
447
- @hostname = hostname
448
- end
516
+ def initialize(
517
+ username: self.class.username,
518
+ password: self.class.password,
519
+ port: self.class.port,
520
+ hostname: self.class.hostname
521
+ )
522
+ @username = username
523
+ @password = password
524
+ @port = port
525
+ @hostname = hostname
449
526
  end
527
+ end
450
528
 
451
- ENV['SERVICE_USERNAME'] = 'my-login'
452
- ENV['SERVICE_HOSTNAME'] = 'host.com'
529
+ ENV['SERVICE_USERNAME'] = 'my-login'
530
+ ENV['SERVICE_HOSTNAME'] = 'host.com'
453
531
 
454
- ServiceClient.default # returns #<ServiceClient:0x0000556fa1b366e8 @username="my-login", @password=nil, @port=80, @hostname="host.com">'
532
+ ServiceClient.default # returns #<ServiceClient:0x0000556fa1b366e8 @username="my-login", @password=nil, @port=80, @hostname="host.com">'
455
533
  ```
534
+ </details>
456
535
 
457
536
  ### Sinclair::Options
458
537
  Options allows projects to have an easy to configure option object
459
538
 
539
+ <details>
540
+ <summary>Example of using Options</summary>
541
+
460
542
  ```ruby
461
- class ConnectionOptions < Sinclair::Options
462
- with_options :timeout, :retries, port: 443, protocol: 'https'
543
+ class ConnectionOptions < Sinclair::Options
544
+ with_options :timeout, :retries, port: 443, protocol: 'https'
463
545
 
464
- # skip_validation if you dont want to validate intialization arguments
465
- end
546
+ # skip_validation if you dont want to validate intialization arguments
547
+ end
466
548
 
467
- options = ConnectionOptions.new(
468
- timeout: 10,
469
- protocol: 'http'
470
- )
549
+ options = ConnectionOptions.new(
550
+ timeout: 10,
551
+ protocol: 'http'
552
+ )
471
553
 
472
- options.timeout # returns 10
473
- options.retries # returns nil
474
- options.protocol # returns 'http'
475
- options.port # returns 443
554
+ options.timeout # returns 10
555
+ options.retries # returns nil
556
+ options.protocol # returns 'http'
557
+ options.port # returns 443
476
558
 
477
- ConnectionOptions.new(invalid: 10) # raises Sinclair::Exception::InvalidOptions
559
+ ConnectionOptions.new(invalid: 10) # raises Sinclair::Exception::InvalidOptions
478
560
  ```
561
+ </details>
479
562
 
480
563
  ### Sinclair::Comparable
481
564
  Comparable allows a class to implement quickly a `==` method comparing given attributes
482
565
 
566
+ <details>
567
+ <summary>Example of Comparable usage</summary>
568
+
483
569
  ```ruby
484
- class SampleModel
485
- include Sinclair::Comparable
570
+ class SampleModel
571
+ include Sinclair::Comparable
486
572
 
487
- comparable_by :name
488
- attr_reader :name, :age
573
+ comparable_by :name
574
+ attr_reader :name, :age
489
575
 
490
- def initialize(name: nil, age: nil)
491
- @name = name
492
- @age = age
493
- end
576
+ def initialize(name: nil, age: nil)
577
+ @name = name
578
+ @age = age
494
579
  end
580
+ end
495
581
 
496
- model1 = model_class.new(name: 'jack', age: 21)
497
- model2 = model_class.new(name: 'jack', age: 23)
582
+ model1 = model_class.new(name: 'jack', age: 21)
583
+ model2 = model_class.new(name: 'jack', age: 23)
498
584
 
499
- model1 == model2 # returns true
585
+ model1 == model2 # returns true
500
586
  ```
587
+ </details>
501
588
 
502
589
  RSspec matcher
503
590
  ---------------
504
591
 
505
592
  You can use the provided matcher to check that your builder is adding a method correctly
506
593
 
594
+ <details>
595
+ <summary>Sample of specs over adding methods</summary>
596
+
507
597
  ```ruby
508
- class DefaultValue
509
- delegate :build, to: :builder
510
- attr_reader :klass, :method, :value, :class_method
511
-
512
- def initialize(klass, method, value, class_method: false)
513
- @klass = klass
514
- @method = method
515
- @value = value
516
- @class_method = class_method
517
- end
598
+ class DefaultValue
599
+ delegate :build, to: :builder
600
+ attr_reader :klass, :method, :value, :class_method
601
+
602
+ def initialize(klass, method, value, class_method: false)
603
+ @klass = klass
604
+ @method = method
605
+ @value = value
606
+ @class_method = class_method
607
+ end
518
608
 
519
- private
609
+ private
520
610
 
521
- def builder
522
- @builder ||= Sinclair.new(klass).tap do |b|
523
- if class_method
524
- b.add_class_method(method) { value }
525
- else
526
- b.add_method(method) { value }
527
- end
611
+ def builder
612
+ @builder ||= Sinclair.new(klass).tap do |b|
613
+ if class_method
614
+ b.add_class_method(method) { value }
615
+ else
616
+ b.add_method(method) { value }
528
617
  end
529
618
  end
530
619
  end
620
+ end
531
621
 
532
- RSpec.describe Sinclair::Matchers do
533
- subject(:builder_class) { DefaultValue }
622
+ RSpec.describe Sinclair::Matchers do
623
+ subject(:builder_class) { DefaultValue }
534
624
 
535
- let(:klass) { Class.new }
536
- let(:method) { :the_method }
537
- let(:value) { Random.rand(100) }
538
- let(:builder) { builder_class.new(klass, method, value) }
539
- let(:instance) { klass.new }
625
+ let(:klass) { Class.new }
626
+ let(:method) { :the_method }
627
+ let(:value) { Random.rand(100) }
628
+ let(:builder) { builder_class.new(klass, method, value) }
629
+ let(:instance) { klass.new }
540
630
 
541
- context 'when the builder runs' do
542
- it do
543
- expect { builder.build }.to add_method(method).to(instance)
544
- end
631
+ context 'when the builder runs' do
632
+ it do
633
+ expect { builder.build }.to add_method(method).to(instance)
545
634
  end
635
+ end
546
636
 
547
- context 'when the builder runs' do
548
- it do
549
- expect { builder.build }.to add_method(method).to(klass)
550
- end
637
+ context 'when the builder runs' do
638
+ it do
639
+ expect { builder.build }.to add_method(method).to(klass)
551
640
  end
641
+ end
552
642
 
553
- context 'when adding class methods' do
554
- subject(:builder) { builder_class.new(klass, method, value, class_method: true) }
643
+ context 'when adding class methods' do
644
+ subject(:builder) { builder_class.new(klass, method, value, class_method: true) }
555
645
 
556
- context 'when the builder runs' do
557
- it do
558
- expect { builder.build }.to add_class_method(method).to(klass)
559
- end
646
+ context 'when the builder runs' do
647
+ it do
648
+ expect { builder.build }.to add_class_method(method).to(klass)
560
649
  end
561
650
  end
562
651
  end
652
+ end
563
653
  ```
564
654
 
565
655
  ```bash
566
-
567
656
  > bundle exec rspec
568
657
  ```
569
658
 
@@ -577,10 +666,11 @@ Sinclair::Matchers
577
666
  when the builder runs
578
667
  should add method class_method 'the_method' to #<Class:0x000055e5d9b95d88>
579
668
  ```
669
+ </details>
580
670
 
581
671
  Projects Using
582
672
  ---------------
583
673
 
584
- - [Arstotzka](https://github.com/darthjee/arstotzka)
585
- - [Azeroth](https://github.com/darthjee/azeroth)
586
- - [Magicka](https://github.com/darthjee/magicka)
674
+ - [Arstotzka](https://github.com/darthjee/arstotzka)
675
+ - [Azeroth](https://github.com/darthjee/azeroth)
676
+ - [Magicka](https://github.com/darthjee/magicka)