sinclair 1.10.0 → 1.12.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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/README.md +444 -324
  4. data/config/check_specs.yml +5 -5
  5. data/config/yardstick.yml +4 -0
  6. data/lib/sinclair/matchers/add_class_method.rb +0 -1
  7. data/lib/sinclair/method_builder/base.rb +32 -2
  8. data/lib/sinclair/method_builder/block_method_builder.rb +1 -12
  9. data/lib/sinclair/method_builder/call_method_builder.rb +10 -27
  10. data/lib/sinclair/method_builder/string_method_builder.rb +2 -29
  11. data/lib/sinclair/method_builder.rb +4 -20
  12. data/lib/sinclair/method_definition/block_definition.rb +2 -0
  13. data/lib/sinclair/method_definition/call_definition.rb +15 -18
  14. data/lib/sinclair/method_definition/parameter_builder.rb +89 -0
  15. data/lib/sinclair/method_definition/parameter_helper.rb +124 -0
  16. data/lib/sinclair/method_definition/string_definition.rb +26 -2
  17. data/lib/sinclair/method_definition.rb +42 -3
  18. data/lib/sinclair/method_definitions.rb +20 -22
  19. data/lib/sinclair/version.rb +1 -1
  20. data/lib/sinclair.rb +149 -62
  21. data/spec/integration/readme/sinclair/types_of_definition_spec.rb +61 -0
  22. data/spec/integration/yard/sinclair/add_class_method_spec.rb +51 -0
  23. data/spec/integration/yard/sinclair/add_method_spec.rb +60 -0
  24. data/spec/integration/yard/sinclair/eval_and_add_method_spec.rb +26 -0
  25. data/spec/integration/yard/sinclair_spec.rb +0 -83
  26. data/spec/lib/sinclair/method_builder/base_spec.rb +15 -0
  27. data/spec/lib/sinclair/method_builder/string_method_builder_spec.rb +24 -1
  28. data/spec/lib/sinclair/method_definition/call_definition_spec.rb +14 -17
  29. data/spec/lib/sinclair/method_definition/parameter_builder_spec.rb +81 -0
  30. data/spec/lib/sinclair/method_definition/string_definition_spec.rb +60 -29
  31. data/spec/lib/sinclair/method_definition_spec.rb +77 -2
  32. data/spec/lib/sinclair/method_definitions_spec.rb +15 -16
  33. data/spec/lib/sinclair_spec.rb +6 -160
  34. data/spec/support/models/dummy_builder.rb +5 -1
  35. data/spec/support/models/dummy_class_builder.rb +4 -0
  36. data/spec/support/models/person.rb +1 -1
  37. data/spec/support/shared_examples/sinclair.rb +118 -0
  38. metadata +11 -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.12.0](https://github.com/darthjee/sinclair/tree/1.12.0)
17
+
18
+ [Next release](https://github.com/darthjee/sinclair/compare/1.12.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.12.0](https://www.rubydoc.info/gems/sinclair/1.12.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
80
+ class HttpJsonModel
81
+ attr_reader :json
76
82
 
77
- class << self
78
- def parse(attribute, path: [])
79
- builder = Sinclair.new(self)
80
-
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
92
 
91
- def initialize(json)
92
- @json = json
93
- end
94
-
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,103 @@ 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
248
259
  ```
249
260
 
250
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
269
+ ```
270
+ </details>
251
271
 
252
- invalid_object = MyClass.new(
253
- name: 'name',
254
- surname: 'surname',
255
- age: 20,
256
- legs: 2
257
- )
258
- invalid_object.valid? # returns false
272
+ #### Different ways of adding the methods
273
+ There are different ways to add a method, each accepting different options
274
+
275
+ <details>
276
+ <summary>Define method using block</summary>
277
+
278
+ Block methods accepts, as option
279
+ - [cache](#caching-the-result): defining the cashing of results
280
+
281
+ ```ruby
282
+ klass = Class.new
283
+ instance = klass.new
284
+
285
+ builder = Sinclair.new(klass)
286
+ builder.add_method(:random_number) { Random.rand(10..20) }
287
+ builder.build
288
+
289
+ instance.random_number # returns a number between 10 and 20
290
+ ```
291
+ </details>
292
+
293
+ <details>
294
+ <summary>Define method using string</summary>
295
+
296
+ String methods accepts, as option
297
+ - [cache](#caching-the-result): defining the cashing of results
298
+ - parameters: defining accepted parameters
299
+ - named_parameters: defining accepted named parameters
300
+
301
+ ```ruby
302
+ # Example without parameters
303
+
304
+ class MyClass
305
+ end
306
+ instance = MyClass.new
307
+
308
+ builder = Sinclair.new(MyClass)
309
+ builder.add_method(:random_number, "Random.rand(10..20)")
310
+ builder.build
311
+
312
+ instance.random_number # returns a number between 10 and 20
313
+ ```
314
+
315
+ ```ruby
316
+ # Example with parameters
317
+
318
+ class MyClass
319
+ end
320
+
321
+ builder = described_class.new(MyClass)
322
+ builder.add_class_method(
323
+ :function, 'a ** b + c', parameters: [:a], named_parameters: [:b, { c: 15 }]
324
+ )
325
+ builder.build
326
+
327
+ MyClass.function(10, b: 2) # returns 115
328
+ ```
329
+ </details>
330
+
331
+ <details>
332
+ <summary>Define method using a call to the class</summary>
333
+
334
+ Call method definitions right now have no options available
335
+
336
+ ```ruby
337
+ class MyClass
338
+ end
339
+
340
+ builder = Sinclair.new(MyClass)
341
+ builder.add_class_method(:attr_accessor, :number, type: :call)
342
+ builder.build
343
+
344
+ MyClass.number # returns nil
345
+ MyClass.number = 10
346
+ MyClass.number # returns 10
259
347
  ```
348
+ </details>
260
349
 
261
350
  #### Caching the result
262
351
  If wanted, the result of the method can be stored in an
@@ -265,87 +354,95 @@ instance variable with the same name.
265
354
  When caching, you can cache with type `:full` so that even `nil`
266
355
  values are cached
267
356
 
357
+ <details>
358
+ <summary>Example of simple cache usage</summary>
359
+
268
360
  ```ruby
269
- class MyModel
270
- attr_accessor :base, :expoent
271
- end
361
+ class MyModel
362
+ attr_accessor :base, :expoent
363
+ end
272
364
 
273
- builder = Sinclair.new(MyModel)
365
+ builder = Sinclair.new(MyModel)
274
366
 
275
- builder.add_method(:cached_power, cached: true) do
276
- base ** expoent
277
- end
367
+ builder.add_method(:cached_power, cached: true) do
368
+ base ** expoent
369
+ end
278
370
 
279
- # equivalent of builder.add_method(:cached_power) do
280
- # @cached_power ||= base ** expoent
281
- # end
371
+ # equivalent of builder.add_method(:cached_power) do
372
+ # @cached_power ||= base ** expoent
373
+ # end
282
374
 
283
- builder.build
375
+ builder.build
284
376
 
285
- model.base = 3
286
- model.expoent = 2
377
+ model.base = 3
378
+ model.expoent = 2
287
379
 
288
- model.cached_power # returns 9
289
- model.expoent = 3
290
- model.cached_power # returns 9 (from cache)
380
+ model.cached_power # returns 9
381
+ model.expoent = 3
382
+ model.cached_power # returns 9 (from cache)
291
383
  ```
384
+ </details>
385
+
386
+ <details>
387
+ <summary>Usage of different cache types</summary>
292
388
 
293
389
  ```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
390
+ module DefaultValueable
391
+ def default_reader(*methods, value:, accept_nil: false)
392
+ DefaultValueBuilder.new(
393
+ self, value: value, accept_nil: accept_nil
394
+ ).add_default_values(*methods)
300
395
  end
396
+ end
301
397
 
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
398
+ class DefaultValueBuilder < Sinclair
399
+ def add_default_values(*methods)
400
+ default_value = value
309
401
 
310
- build
402
+ methods.each do |method|
403
+ add_method(method, cached: cache_type) { default_value }
311
404
  end
312
405
 
313
- private
406
+ build
407
+ end
314
408
 
315
- delegate :accept_nil, :value, to: :options_object
409
+ private
316
410
 
317
- def cache_type
318
- accept_nil ? :full : :simple
319
- end
411
+ delegate :accept_nil, :value, to: :options_object
412
+
413
+ def cache_type
414
+ accept_nil ? :full : :simple
320
415
  end
416
+ end
321
417
 
322
- class Server
323
- extend DefaultValueable
418
+ class Server
419
+ extend DefaultValueable
324
420
 
325
- attr_writer :host, :port
421
+ attr_writer :host, :port
326
422
 
327
- default_reader :host, value: 'server.com', accept_nil: false
328
- default_reader :port, value: 80, accept_nil: true
423
+ default_reader :host, value: 'server.com', accept_nil: false
424
+ default_reader :port, value: 80, accept_nil: true
329
425
 
330
- def url
331
- return "http://#{host}" unless port
426
+ def url
427
+ return "http://#{host}" unless port
332
428
 
333
- "http://#{host}:#{port}"
334
- end
429
+ "http://#{host}:#{port}"
335
430
  end
431
+ end
336
432
 
337
- server = Server.new
433
+ server = Server.new
338
434
 
339
- server.url # returns 'http://server.com:80'
435
+ server.url # returns 'http://server.com:80'
340
436
 
341
- server.host = 'interstella.com'
342
- server.port = 5555
343
- server.url # returns 'http://interstella.com:5555'
437
+ server.host = 'interstella.com'
438
+ server.port = 5555
439
+ server.url # returns 'http://interstella.com:5555'
344
440
 
345
- server.host = nil
346
- server.port = nil
347
- server.url # return 'http://server.com'
441
+ server.host = nil
442
+ server.port = nil
443
+ server.url # return 'http://server.com'
348
444
  ```
445
+ </details>
349
446
 
350
447
  ### Sinclair::Configurable
351
448
 
@@ -356,214 +453,236 @@ Configurations are read-only objects that can only be set using
356
453
  the `configurable#configure` method which accepts a block or
357
454
  hash
358
455
 
456
+ <details>
457
+ <summary>Using configurable</summary>
458
+
359
459
  ```ruby
360
- module MyConfigurable
361
- extend Sinclair::Configurable
460
+ module MyConfigurable
461
+ extend Sinclair::Configurable
362
462
 
363
- # port is defaulted to 80
364
- configurable_with :host, port: 80
365
- end
463
+ # port is defaulted to 80
464
+ configurable_with :host, port: 80
465
+ end
366
466
 
367
- MyConfigurable.configure(port: 5555) do |config|
368
- config.host 'interstella.art'
369
- end
467
+ MyConfigurable.configure(port: 5555) do |config|
468
+ config.host 'interstella.art'
469
+ end
370
470
 
371
- MyConfigurable.config.host # returns 'interstella.art'
372
- MyConfigurable.config.port # returns 5555
471
+ MyConfigurable.config.host # returns 'interstella.art'
472
+ MyConfigurable.config.port # returns 5555
373
473
 
374
- # Configurable enables options that can be passed
375
- MyConfigurable.as_options.host # returns 'interstella.art'
474
+ # Configurable enables options that can be passed
475
+ MyConfigurable.as_options.host # returns 'interstella.art'
376
476
 
377
- # Configurable enables options that can be passed with custom values
378
- MyConfigurable.as_options(host: 'other').host # returns 'other'
477
+ # Configurable enables options that can be passed with custom values
478
+ MyConfigurable.as_options(host: 'other').host # returns 'other'
379
479
 
380
- MyConfigurable.reset_config
480
+ MyConfigurable.reset_config
381
481
 
382
- MyConfigurable.config.host # returns nil
383
- MyConfigurable.config.port # returns 80
482
+ MyConfigurable.config.host # returns nil
483
+ MyConfigurable.config.port # returns 80
384
484
  ```
485
+ </details>
385
486
 
386
487
  Configurations can also be done through custom classes
387
488
 
388
- ```ruby
389
- class MyServerConfig < Sinclair::Config
390
- config_attributes :host, :port
489
+ <details>
490
+ <summary>Using configration class</summary>
391
491
 
392
- def url
393
- if @port
394
- "http://#{@host}:#{@port}"
395
- else
396
- "http://#{@host}"
397
- end
492
+ ```ruby
493
+ class MyServerConfig < Sinclair::Config
494
+ config_attributes :host, :port
495
+
496
+ def url
497
+ if @port
498
+ "http://#{@host}:#{@port}"
499
+ else
500
+ "http://#{@host}"
398
501
  end
399
502
  end
503
+ end
400
504
 
401
- class Client
402
- extend Sinclair::Configurable
505
+ class Client
506
+ extend Sinclair::Configurable
403
507
 
404
- configurable_by MyServerConfig
405
- end
508
+ configurable_by MyServerConfig
509
+ end
406
510
 
407
- Client.configure do
408
- host 'interstella.com'
409
- end
511
+ Client.configure do
512
+ host 'interstella.com'
513
+ end
410
514
 
411
- Client.config.url # returns 'http://interstella.com'
515
+ Client.config.url # returns 'http://interstella.com'
412
516
 
413
- Client.configure do |config|
414
- config.port 8080
415
- end
517
+ Client.configure do |config|
518
+ config.port 8080
519
+ end
416
520
 
417
- Client.config.url # returns 'http://interstella.com:8080'
521
+ Client.config.url # returns 'http://interstella.com:8080'
418
522
  ```
523
+ </details>
419
524
 
420
525
  ### Sinclair::EnvSettable
421
526
 
422
527
  Settable allows classes to extract configuration from environments through
423
528
  a simple meta-programable way
424
529
 
530
+ <details>
531
+ <summary>Using env settable example</summary>
532
+
425
533
  ```ruby
426
- class ServiceClient
427
- extend Sinclair::EnvSettable
428
- attr_reader :username, :password, :host, :port
534
+ class ServiceClient
535
+ extend Sinclair::EnvSettable
536
+ attr_reader :username, :password, :host, :port
429
537
 
430
- settings_prefix 'SERVICE'
538
+ settings_prefix 'SERVICE'
431
539
 
432
- with_settings :username, :password, port: 80, hostname: 'my-host.com'
540
+ with_settings :username, :password, port: 80, hostname: 'my-host.com'
433
541
 
434
- def self.default
435
- @default ||= new
436
- end
542
+ def self.default
543
+ @default ||= new
544
+ end
437
545
 
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
546
+ def initialize(
547
+ username: self.class.username,
548
+ password: self.class.password,
549
+ port: self.class.port,
550
+ hostname: self.class.hostname
551
+ )
552
+ @username = username
553
+ @password = password
554
+ @port = port
555
+ @hostname = hostname
449
556
  end
557
+ end
450
558
 
451
- ENV['SERVICE_USERNAME'] = 'my-login'
452
- ENV['SERVICE_HOSTNAME'] = 'host.com'
559
+ ENV['SERVICE_USERNAME'] = 'my-login'
560
+ ENV['SERVICE_HOSTNAME'] = 'host.com'
453
561
 
454
- ServiceClient.default # returns #<ServiceClient:0x0000556fa1b366e8 @username="my-login", @password=nil, @port=80, @hostname="host.com">'
562
+ ServiceClient.default # returns #<ServiceClient:0x0000556fa1b366e8 @username="my-login", @password=nil, @port=80, @hostname="host.com">'
455
563
  ```
564
+ </details>
456
565
 
457
566
  ### Sinclair::Options
458
567
  Options allows projects to have an easy to configure option object
459
568
 
569
+ <details>
570
+ <summary>Example of using Options</summary>
571
+
460
572
  ```ruby
461
- class ConnectionOptions < Sinclair::Options
462
- with_options :timeout, :retries, port: 443, protocol: 'https'
573
+ class ConnectionOptions < Sinclair::Options
574
+ with_options :timeout, :retries, port: 443, protocol: 'https'
463
575
 
464
- # skip_validation if you dont want to validate intialization arguments
465
- end
576
+ # skip_validation if you dont want to validate intialization arguments
577
+ end
466
578
 
467
- options = ConnectionOptions.new(
468
- timeout: 10,
469
- protocol: 'http'
470
- )
579
+ options = ConnectionOptions.new(
580
+ timeout: 10,
581
+ protocol: 'http'
582
+ )
471
583
 
472
- options.timeout # returns 10
473
- options.retries # returns nil
474
- options.protocol # returns 'http'
475
- options.port # returns 443
584
+ options.timeout # returns 10
585
+ options.retries # returns nil
586
+ options.protocol # returns 'http'
587
+ options.port # returns 443
476
588
 
477
- ConnectionOptions.new(invalid: 10) # raises Sinclair::Exception::InvalidOptions
589
+ ConnectionOptions.new(invalid: 10) # raises Sinclair::Exception::InvalidOptions
478
590
  ```
591
+ </details>
479
592
 
480
593
  ### Sinclair::Comparable
481
594
  Comparable allows a class to implement quickly a `==` method comparing given attributes
482
595
 
596
+ <details>
597
+ <summary>Example of Comparable usage</summary>
598
+
483
599
  ```ruby
484
- class SampleModel
485
- include Sinclair::Comparable
600
+ class SampleModel
601
+ include Sinclair::Comparable
486
602
 
487
- comparable_by :name
488
- attr_reader :name, :age
603
+ comparable_by :name
604
+ attr_reader :name, :age
489
605
 
490
- def initialize(name: nil, age: nil)
491
- @name = name
492
- @age = age
493
- end
606
+ def initialize(name: nil, age: nil)
607
+ @name = name
608
+ @age = age
494
609
  end
610
+ end
495
611
 
496
- model1 = model_class.new(name: 'jack', age: 21)
497
- model2 = model_class.new(name: 'jack', age: 23)
612
+ model1 = model_class.new(name: 'jack', age: 21)
613
+ model2 = model_class.new(name: 'jack', age: 23)
498
614
 
499
- model1 == model2 # returns true
615
+ model1 == model2 # returns true
500
616
  ```
617
+ </details>
501
618
 
502
619
  RSspec matcher
503
620
  ---------------
504
621
 
505
622
  You can use the provided matcher to check that your builder is adding a method correctly
506
623
 
624
+ <details>
625
+ <summary>Sample of specs over adding methods</summary>
626
+
507
627
  ```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
628
+ class DefaultValue
629
+ delegate :build, to: :builder
630
+ attr_reader :klass, :method, :value, :class_method
631
+
632
+ def initialize(klass, method, value, class_method: false)
633
+ @klass = klass
634
+ @method = method
635
+ @value = value
636
+ @class_method = class_method
637
+ end
518
638
 
519
- private
639
+ private
520
640
 
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
641
+ def builder
642
+ @builder ||= Sinclair.new(klass).tap do |b|
643
+ if class_method
644
+ b.add_class_method(method) { value }
645
+ else
646
+ b.add_method(method) { value }
528
647
  end
529
648
  end
530
649
  end
650
+ end
531
651
 
532
- RSpec.describe Sinclair::Matchers do
533
- subject(:builder_class) { DefaultValue }
652
+ RSpec.describe Sinclair::Matchers do
653
+ subject(:builder_class) { DefaultValue }
534
654
 
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 }
655
+ let(:klass) { Class.new }
656
+ let(:method) { :the_method }
657
+ let(:value) { Random.rand(100) }
658
+ let(:builder) { builder_class.new(klass, method, value) }
659
+ let(:instance) { klass.new }
540
660
 
541
- context 'when the builder runs' do
542
- it do
543
- expect { builder.build }.to add_method(method).to(instance)
544
- end
661
+ context 'when the builder runs' do
662
+ it do
663
+ expect { builder.build }.to add_method(method).to(instance)
545
664
  end
665
+ end
546
666
 
547
- context 'when the builder runs' do
548
- it do
549
- expect { builder.build }.to add_method(method).to(klass)
550
- end
667
+ context 'when the builder runs' do
668
+ it do
669
+ expect { builder.build }.to add_method(method).to(klass)
551
670
  end
671
+ end
552
672
 
553
- context 'when adding class methods' do
554
- subject(:builder) { builder_class.new(klass, method, value, class_method: true) }
673
+ context 'when adding class methods' do
674
+ subject(:builder) { builder_class.new(klass, method, value, class_method: true) }
555
675
 
556
- context 'when the builder runs' do
557
- it do
558
- expect { builder.build }.to add_class_method(method).to(klass)
559
- end
676
+ context 'when the builder runs' do
677
+ it do
678
+ expect { builder.build }.to add_class_method(method).to(klass)
560
679
  end
561
680
  end
562
681
  end
682
+ end
563
683
  ```
564
684
 
565
685
  ```bash
566
-
567
686
  > bundle exec rspec
568
687
  ```
569
688
 
@@ -577,10 +696,11 @@ Sinclair::Matchers
577
696
  when the builder runs
578
697
  should add method class_method 'the_method' to #<Class:0x000055e5d9b95d88>
579
698
  ```
699
+ </details>
580
700
 
581
701
  Projects Using
582
702
  ---------------
583
703
 
584
- - [Arstotzka](https://github.com/darthjee/arstotzka)
585
- - [Azeroth](https://github.com/darthjee/azeroth)
586
- - [Magicka](https://github.com/darthjee/magicka)
704
+ - [Arstotzka](https://github.com/darthjee/arstotzka)
705
+ - [Azeroth](https://github.com/darthjee/azeroth)
706
+ - [Magicka](https://github.com/darthjee/magicka)