sinclair 1.3.4 → 1.4.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: 6e1275a6e3f8459ed0176557d4d9580c7cac9bc537b36dd3a96179d43803035b
4
- data.tar.gz: baba86f5fe29bddf70c3d440e0539c4d0aa4a7b892a9548f73dbaf8945d51be7
3
+ metadata.gz: 4826b55d94281092e5a0ba4d397366c39ec3494ec6f84743480c9e6ef69a030e
4
+ data.tar.gz: fbd63c4a98eacaf569a56c95411e71043f5b400bd7f98b593c73fba1a68d5bd6
5
5
  SHA512:
6
- metadata.gz: ca4c580be409552638fb442d63b5036cac1d45134839f00551ea2cdcf1cada5f8736d6e1f2abdda97bd9d850a25d92599791efa15f423496796f30c834db053f
7
- data.tar.gz: 604d5a4c072fff368b8bd6d062ab6730880bef1f29d6d197e00780cf7d8e98d3d6d64a34c87c8d93a1a367ec81a9a3ab98860111d5d425599d2777fb831db7dd
6
+ metadata.gz: 531c6f6db55bed97a3bfcf8f8c6001ae35cd5226aa5e386b0bb9442afcea7984bdf77ef4b16774e6e7c44c4b51c8ec15eac74431042f26a12d069909a2fa6a1f
7
+ data.tar.gz: 5820b843eaddf7838d430c4713645fbad5a8bf46850bc9cce5dbc1cc9f7d0005dc949969c06ba6ed3ca088a9790fdf32121e2e795dcc09935092636594809ed2
data/README.md CHANGED
@@ -14,7 +14,7 @@ methods
14
14
 
15
15
  Yard Documentation
16
16
  -------------------
17
- https://www.rubydoc.info/gems/sinclair/1.3.4
17
+ https://www.rubydoc.info/gems/sinclair/1.4.0
18
18
 
19
19
  Installation
20
20
  ---------------
@@ -335,7 +335,9 @@ the `configurable#configure` method
335
335
  Configurations can also be done through custom classes
336
336
 
337
337
  ```ruby
338
- class MyServerConfig
338
+ class MyServerConfig < Sinclair::Config
339
+ config_attributes :host, :port
340
+
339
341
  def url
340
342
  if @port
341
343
  "http://#{@host}:#{@port}"
@@ -348,7 +350,7 @@ Configurations can also be done through custom classes
348
350
  class Client
349
351
  extend Sinclair::Configurable
350
352
 
351
- configurable_by MyServerConfig, with: %i[host port]
353
+ configurable_by MyServerConfig
352
354
  end
353
355
 
354
356
  Client.configure do
data/WARNINGS.md ADDED
@@ -0,0 +1,69 @@
1
+ # Warnings
2
+ This documents tries to bring more information on warnings
3
+ and depreations on current versions of the gem.
4
+
5
+ ## Usage of custom config classes
6
+ Introduced: 1.3.0
7
+ Changed in: 1.4.0
8
+
9
+ In the past, you could use any custom configuration classes
10
+ to configure your configurable. Those classes could be
11
+ extended through the regular usage of ```.configurable_with```
12
+ or have it's configuration attributes declared by
13
+ ```with``` option on ```configurable_with```
14
+
15
+ ```ruby
16
+ class MyConfig
17
+ def url
18
+ if @port
19
+ "http://#{@host}:#{@port}"
20
+ else
21
+ "http://#{@host}"
22
+ end
23
+ end
24
+ end
25
+
26
+ class MyClient
27
+ configutable_by MyConfig, with: [:host, :port]
28
+ configurable_with timeout: 5.seconds
29
+ end
30
+
31
+ MyClient.configure do
32
+ port 5555
33
+ host 'myhost.com'
34
+ timeout 10.seconds
35
+ end
36
+ ```
37
+
38
+ Now, the configuration class should extend ```Sinclair::ConfigClass```
39
+ and the attributes defined within the class itself, still
40
+ being able to extend it through the usage of
41
+ ```.configurable_with``` call after ```configurable_by```
42
+
43
+ ```ruby
44
+ class MyConfig
45
+ extend Sinclair::ConfigClass
46
+
47
+ config_attributes :host, :port
48
+
49
+ def url
50
+ if @port
51
+ "http://#{@host}:#{@port}"
52
+ else
53
+ "http://#{@host}"
54
+ end
55
+ end
56
+ end
57
+
58
+ class MyClient
59
+ configutable_by MyConfig
60
+
61
+ configurable_with timeout: 5.seconds
62
+ end
63
+
64
+ MyClient.configure do
65
+ port 5555
66
+ host 'myhost.com'
67
+ timeout 10.seconds
68
+ end
69
+ ```
data/config/yardstick.yml CHANGED
@@ -37,8 +37,8 @@ rules:
37
37
  - Sinclair::ConfigFactory#initialize
38
38
  - Sinclair::ConfigFactory#config_class
39
39
  - Sinclair::ConfigFactory#config_attributes
40
- - Sinclair::ConfigFactory::MethodsBuilder#names
41
- - Sinclair::ConfigFactory::MethodsBuilder#defaults
40
+ - Sinclair::Config::MethodsBuilder#names
41
+ - Sinclair::Config::MethodsBuilder#defaults
42
42
  - Sinclair::Configurable#config
43
43
  - Sinclair::Configurable#reset_config
44
44
  - Sinclair::Configurable#configure
@@ -60,9 +60,9 @@ rules:
60
60
  - Sinclair::ConfigFactory#initialize
61
61
  - Sinclair::ConfigFactory#config_class
62
62
  - Sinclair::ConfigFactory#config_attributes
63
- - Sinclair::ConfigFactory::MethodsBuilder#initialize
64
- - Sinclair::ConfigFactory::MethodsBuilder#names
65
- - Sinclair::ConfigFactory::MethodsBuilder#defaults
63
+ - Sinclair::Config::MethodsBuilder#initialize
64
+ - Sinclair::Config::MethodsBuilder#names
65
+ - Sinclair::Config::MethodsBuilder#defaults
66
66
  Summary::Length:
67
67
  enabled: true
68
68
  exclude: []
data/lib/sinclair.rb CHANGED
@@ -86,6 +86,7 @@ class Sinclair
86
86
  autoload :MethodDefinition, 'sinclair/method_definition'
87
87
  autoload :Config, 'sinclair/config'
88
88
  autoload :ConfigBuilder, 'sinclair/config_builder'
89
+ autoload :ConfigClass, 'sinclair/config_class'
89
90
  autoload :ConfigFactory, 'sinclair/config_factory'
90
91
  autoload :Configurable, 'sinclair/configurable'
91
92
 
@@ -7,5 +7,32 @@ class Sinclair
7
7
  #
8
8
  # The instance variables will be set by {ConfigBuilder}
9
9
  class Config
10
+ autoload :MethodsBuilder, 'sinclair/config/methods_builder'
11
+ extend ConfigClass
12
+
13
+ # Return all the current configurations in a hash
14
+ #
15
+ # @return [Hash]
16
+ #
17
+ # @example Checking all hash/json formats
18
+ # class LoginConfig < Sinclair::Config
19
+ # add_configs :password, username: 'bob'
20
+ # end
21
+ #
22
+ # config = LoginConfig.new
23
+ #
24
+ # config.to_hash
25
+ # # returns { 'password' => nil, 'username' => 'bob' }
26
+ #
27
+ # config.as_json
28
+ # # returns { 'password' => nil, 'username' => 'bob' }
29
+ #
30
+ # config.to_json
31
+ # # returns '{"password":null,"username":"bob"}'
32
+ def to_hash
33
+ self.class.config_attributes.each_with_object({}) do |attribute, hash|
34
+ hash[attribute.to_s] = public_send(attribute)
35
+ end
36
+ end
10
37
  end
11
38
  end
@@ -1,19 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Sinclair
4
- class ConfigFactory
4
+ class Config
5
5
  # @api private
6
6
  #
7
7
  # Class responsible for adding method to configuration
8
8
  # classes
9
9
  class MethodsBuilder < Sinclair
10
+ # Instantiate method builder and build the methods
11
+ #
12
+ # @param (see #initialize)
13
+ #
14
+ # @overload build(klass, *names, default)
15
+ # @param names [Array<Symbol,String>] List of configuration names
16
+ # to be added
17
+ # @param default [Hash] Configurations that will receive a default
18
+ # value when not configured
19
+ #
20
+ # @return [MethodsBuilder]
21
+ def self.build(klass, *names)
22
+ new(klass, *names).tap(&:build)
23
+ end
24
+
10
25
  # @param klass [Class] class inheriting from {Sinclair::Config}
11
26
  # that will receive the methods
12
27
  # @overload initialize(klass, *names, default)
13
28
  # @param names [Array<Symbol,String>] List of configuration names
14
- # to be added
29
+ # to be added
15
30
  # @param default [Hash] Configurations that will receive a default
16
- # value when not configured
31
+ # value when not configured
17
32
  def initialize(klass, *names)
18
33
  super(klass)
19
34
 
@@ -7,6 +7,8 @@ class Sinclair
7
7
  #
8
8
  # @example
9
9
  # class MyConfig
10
+ # extend Sinclair::ConfigClass
11
+ #
10
12
  # attr_reader :name, :config
11
13
  # end
12
14
  #
@@ -47,7 +49,7 @@ class Sinclair
47
49
  #
48
50
  # @return [Object]
49
51
  def method_missing(method_name, *args)
50
- return super unless @config_attributes.include?(method_name)
52
+ return super unless method_included?(method_name)
51
53
 
52
54
  @config.instance_variable_set("@#{method_name}", *args)
53
55
  end
@@ -60,7 +62,21 @@ class Sinclair
60
62
  #
61
63
  # @see #method_missing
62
64
  def respond_to_missing?(method_name, include_private)
63
- @config_attributes.include?(method_name) || super
65
+ method_included?(method_name) || super
66
+ end
67
+
68
+ # Checks if a method is included in the methods defined
69
+ #
70
+ # @param method_name [Symbol] name of the method called
71
+ #
72
+ # @return [TrueClass,FalseClass]
73
+ #
74
+ # @todo get rid of @config_attributes when only
75
+ # Sinclair::ConfigClass are accepted
76
+ def method_included?(method_name)
77
+ @config_attributes.include?(method_name) ||
78
+ @config.class.is_a?(Sinclair::ConfigClass) &&
79
+ @config.class.config_attributes.include?(method_name)
64
80
  end
65
81
  end
66
82
  end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ # @api public
5
+ #
6
+ # Module with all class methods for {Config}
7
+ #
8
+ # Any class that will be used as configuration class
9
+ # should extend {ConfigClass} as {#config_attributes}
10
+ # is used to check what configurations have been added
11
+ #
12
+ # @example (see #add_configs)
13
+ module ConfigClass
14
+ # @api private
15
+ #
16
+ # Adds an attribute to the list of attributes
17
+ #
18
+ # The list of attributes represent attribute
19
+ # readers that class instances can respond to
20
+ #
21
+ # Subclasses will respond to the same attributes as the
22
+ # parent class plus it's own
23
+ #
24
+ # This method does not add the method or .attr_reader
25
+ #
26
+ # @param attributes [Array<Symbol,String>] list of
27
+ # attributes the instances should respond to
28
+ #
29
+ # @return [Array<Symbol>] all attributes the class have
30
+ #
31
+ # @see #attributes
32
+ def config_attributes(*attributes)
33
+ @config_attributes ||= []
34
+
35
+ if attributes.present?
36
+ new_attributes = attributes.map(&:to_sym) - @config_attributes
37
+ @config_attributes.concat(new_attributes)
38
+ end
39
+
40
+ if superclass.is_a?(ConfigClass)
41
+ (superclass.config_attributes.dup + @config_attributes).uniq
42
+ else
43
+ @config_attributes
44
+ end
45
+ end
46
+
47
+ # Add a config attribute
48
+ #
49
+ # This method adds an attribute (see {#config_attributes})
50
+ # and the method readers
51
+ #
52
+ # @overload add_configs(*names, default)
53
+ # @param names [Array<Symbol,String>] List of configuration names
54
+ # to be added
55
+ # @param default [Hash] Configurations that will receive a default
56
+ # value when not configured
57
+ #
58
+ # @return [MethodsBuilder]
59
+ #
60
+ # @see MethodsBuilder#build
61
+ #
62
+ # @example Adding configurations to config class
63
+ # class AppConfig
64
+ # extend Sinclair::ConfigClass
65
+ #
66
+ # add_configs :secret, app_name: 'MyApp'
67
+ # end
68
+ #
69
+ # config = AppConfig.new
70
+ #
71
+ # config.secret
72
+ # # return nil
73
+ #
74
+ # config.app_name
75
+ # # return 'MyApp'
76
+ #
77
+ # config_builder = Sinclair::ConfigBuilder.new(config)
78
+ #
79
+ # config_builder.secret '123abc'
80
+ # config_builder.app_name 'MySuperApp'
81
+ #
82
+ # config.secret
83
+ # # return '123abc'
84
+ #
85
+ # config.app_name
86
+ # # return 'MySuperApp'
87
+ def add_configs(*args)
88
+ Config::MethodsBuilder.new(self, *args).tap do |builder|
89
+ builder.build
90
+
91
+ config_attributes(*builder.config_names)
92
+ end
93
+ end
94
+ end
95
+ end
@@ -16,13 +16,20 @@ class Sinclair
16
16
  # factory.config.equal?(config) # returns true
17
17
  # config.name # returns 'John'
18
18
  class ConfigFactory
19
- autoload :MethodsBuilder, 'sinclair/config_factory/methods_builder'
20
-
19
+ # @api private
20
+ # Deprecation warning message
21
+ # @see https://github.com/darthjee/sinclair/blob/master/WARNINGS.md#usage-of-custom-config-classes
22
+ CONFIG_CLASS_WARNING = 'Config class is expected to be ConfigClass. ' \
23
+ "In future releases this will be enforced.\n" \
24
+ 'see more on https://github.com/darthjee/sinclair/blob/master/WARNINGS.md#usage-of-custom-config-classes'
21
25
  # @param config_class [Class] configuration class to be used
22
26
  # @param config_attributes [Array<Symbol,String>] list of possible configurations
23
27
  def initialize(config_class: Class.new(Config), config_attributes: [])
24
28
  @config_class = config_class
25
29
  @config_attributes = config_attributes.dup
30
+
31
+ return if config_class.is_a?(ConfigClass)
32
+ warn CONFIG_CLASS_WARNING
26
33
  end
27
34
 
28
35
  # @api public
@@ -71,6 +78,8 @@ class Sinclair
71
78
  # {ConfigBuilder} is able to set those values when invoked
72
79
  #
73
80
  # @return [Array<Symbol>] all known config attributes
81
+ # @todo remove class check once only
82
+ # ConfigClass are accepted
74
83
  #
75
84
  # @example Adding configuration name
76
85
  # factory = Sinclair::ConfigFactory.new
@@ -84,9 +93,11 @@ class Sinclair
84
93
  # config.respond_to? :active
85
94
  # # returns true
86
95
  def add_configs(*args)
87
- builder = MethodsBuilder.new(config_class, *args)
88
-
89
- builder.build
96
+ builder = if config_class.is_a?(Sinclair::ConfigClass)
97
+ config_class.add_configs(*args)
98
+ else
99
+ Config::MethodsBuilder.build(config_class, *args)
100
+ end
90
101
 
91
102
  config_attributes.concat(builder.config_names.map(&:to_sym))
92
103
  end
@@ -107,6 +118,8 @@ class Sinclair
107
118
  #
108
119
  # @example Setting name on config
109
120
  # class MyConfig
121
+ # extend Sinclair::ConfigClass
122
+ #
110
123
  # attr_reader :name
111
124
  # end
112
125
  #
@@ -17,6 +17,14 @@ class Sinclair
17
17
  # @example (see #configurable_with)
18
18
  # @example (see #configurable_by)
19
19
  module Configurable
20
+ # @api private
21
+ # Deprecation warning message
22
+ # @see https://github.com/darthjee/sinclair/blob/master/WARNINGS.md#usage-of-custom-config-classes
23
+ CONFIG_CLASS_WARNING = 'Config classes attributes should ' \
24
+ 'be defined inside the class or through the usage of ' \
25
+ "configurable_with.\n" \
26
+ "In future releases this will be enforced.\n" \
27
+ 'see more on https://github.com/darthjee/sinclair/blob/master/WARNINGS.md#usage-of-custom-config-classes'
20
28
  # (see ConfigFactory#config)
21
29
  # @see ConfigFactory#config
22
30
  def config
@@ -116,7 +124,9 @@ class Sinclair
116
124
  # @return [ConfigFactory]
117
125
  #
118
126
  # @example Configured by custom config class
119
- # class MyServerConfig
127
+ # class MyServerConfig < Sinclair::Config
128
+ # config_attributes :host, :port
129
+ #
120
130
  # def url
121
131
  # if @port
122
132
  # "http://#{@host}:#{@port}"
@@ -129,7 +139,7 @@ class Sinclair
129
139
  # class Client
130
140
  # extend Sinclair::Configurable
131
141
  #
132
- # configurable_by MyServerConfig, with: %i[host port]
142
+ # configurable_by MyServerConfig
133
143
  # end
134
144
  #
135
145
  # Client.configure do
@@ -144,6 +154,8 @@ class Sinclair
144
154
  #
145
155
  # Client.config.url # returns 'http://interstella.com:8080'
146
156
  def configurable_by(config_class, with: [])
157
+ warn CONFIG_CLASS_WARNING if with.present?
158
+
147
159
  @config_factory = ConfigFactory.new(
148
160
  config_class: config_class,
149
161
  config_attributes: with.map(&:to_sym)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Sinclair
4
- VERSION = '1.3.4'
4
+ VERSION = '1.4.0'
5
5
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'spec_helper'
4
+
3
5
  describe Sinclair::ConfigBuilder do
4
6
  describe 'yard' do
5
7
  describe '#instance_eval' do
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::ConfigClass do
6
+ describe 'yard' do
7
+ describe '.add_configs' do
8
+ subject(:config) { AppConfig.new }
9
+
10
+ it 'has a secret configuration method' do
11
+ expect(config.secret).to be_nil
12
+ end
13
+
14
+ it 'has a app_name configuration method' do
15
+ expect(config.app_name).to eq('MyApp')
16
+ end
17
+
18
+ context 'when configured' do
19
+ let(:config_builder) do
20
+ Sinclair::ConfigBuilder.new(config)
21
+ end
22
+
23
+ before do
24
+ config_builder.secret '123abc'
25
+ config_builder.app_name 'MySuperApp'
26
+ end
27
+
28
+ it 'has a secret configuration method' do
29
+ expect(config.secret).to eq('123abc')
30
+ end
31
+
32
+ it 'has a app_name configuration method' do
33
+ expect(config.app_name).to eq('MySuperApp')
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'spec_helper'
4
+
3
5
  describe Sinclair::ConfigFactory do
4
6
  describe '#yard' do
5
7
  subject(:factory) do
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Config do
6
+ describe 'yard' do
7
+ describe '#to_hash' do
8
+ subject(:config) { config_class.new }
9
+
10
+ let(:config_class) { LoginConfig }
11
+
12
+ it 'returns all configs hash' do
13
+ expect(config.to_hash)
14
+ .to eq('password' => nil, 'username' => 'bob')
15
+ end
16
+
17
+ it 'returns all configs hash on as_json calls' do
18
+ expect(config.as_json)
19
+ .to eq('password' => nil, 'username' => 'bob')
20
+ end
21
+
22
+ it 'returns all configs json on to_json calls' do
23
+ expect(config.to_json)
24
+ .to eq('{"password":null,"username":"bob"}')
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'spec_helper'
4
+
3
5
  describe Sinclair::MethodDefinition do
4
6
  describe 'yard' do
5
7
  describe '#build' do
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Sinclair::ConfigFactory::MethodsBuilder do
5
+ describe Sinclair::Config::MethodsBuilder do
6
6
  describe '#build' do
7
7
  let(:config_class) { Class.new(Sinclair::Config) }
8
8
  let(:config) { config_class.new }
@@ -1,51 +1,88 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'spec_helper'
4
+
3
5
  describe Sinclair::ConfigBuilder do
4
6
  subject(:builder) { described_class.new(config, *config_attributes) }
5
7
 
6
- let(:config) { MyConfig.new }
8
+ let(:config_class) { MyConfig }
9
+ let(:config) { config_class.new }
7
10
  let(:config_attributes) { [:name] }
8
11
 
9
- it 'changes responds to given config' do
10
- expect(builder).to respond_to(:name)
11
- end
12
+ describe '#responds_to' do
13
+ it 'changes responds to given config' do
14
+ expect(builder).to respond_to(:name)
15
+ end
12
16
 
13
- it 'does not respond to othr configs' do
14
- expect(builder).not_to respond_to(:other_method)
15
- end
17
+ it 'does not respond to other configs' do
18
+ expect(builder).not_to respond_to(:other_method)
19
+ end
16
20
 
17
- it 'responds to other parent methods' do
18
- expect(builder).to respond_to(:to_s)
19
- end
21
+ it 'responds to other parent methods' do
22
+ expect(builder).to respond_to(:to_s)
23
+ end
24
+
25
+ context 'when it was instatiated without the attribute' do
26
+ let(:config_attributes) { [] }
27
+
28
+ it 'does not respond to given attribute' do
29
+ expect(builder).not_to respond_to(:name)
30
+ end
20
31
 
21
- context 'when builder was configuratd with the method called' do
22
- let(:config_attributes) { [:name] }
32
+ context 'when class is a ConfigClass and has been configured' do
33
+ let(:config_class) { Class.new(Sinclair::Config) }
23
34
 
24
- it 'sets the instance variable' do
25
- expect { builder.name 'John' }
26
- .to change(config, :name)
27
- .from(nil).to('John')
35
+ before { config_class.config_attributes(:name) }
36
+
37
+ it 'changes responds to given config' do
38
+ expect(builder).to respond_to(:name)
39
+ end
40
+ end
28
41
  end
29
42
  end
30
43
 
31
- context 'when builder was configuratd without the method called' do
32
- let(:config_attributes) { [] }
44
+ describe '#method_missing' do
45
+ context 'when builder was configuratd with the method called' do
46
+ let(:config_attributes) { [:name] }
33
47
 
34
- it 'does not set the instance variable and raises error' do
35
- expect { builder.name 'John' }
36
- .to raise_error(NoMethodError)
37
- .and not_change(config, :name)
48
+ it 'sets the instance variable' do
49
+ expect { builder.name 'John' }
50
+ .to change(config, :name)
51
+ .from(nil).to('John')
52
+ end
53
+ end
54
+
55
+ context 'when builder was configuratd without the method called' do
56
+ let(:config_attributes) { [] }
57
+
58
+ it 'does not set the instance variable and raises error' do
59
+ expect { builder.name 'John' }
60
+ .to raise_error(NoMethodError)
61
+ .and not_change(config, :name)
62
+ end
63
+
64
+ context 'with config class that has been configured with it' do
65
+ let(:config_class) { Class.new(Sinclair::Config) }
66
+
67
+ before { config_class.add_configs(:name) }
68
+
69
+ it 'sets the instance variable' do
70
+ expect { builder.name 'John' }
71
+ .to change(config, :name)
72
+ .from(nil).to('John')
73
+ end
74
+ end
38
75
  end
39
- end
40
76
 
41
- context 'when using a variable name from builder variables' do
42
- let(:config_attributes) { [:config] }
77
+ context 'when using a variable name from builder variables' do
78
+ let(:config_attributes) { [:config] }
43
79
 
44
- it 'sets the instance variable without changing builder instance variable' do
45
- expect { builder.config(key: 'value') }
46
- .to not_change { builder.instance_variable_get(:@config) }
47
- .and change(config, :config)
48
- .from(nil).to(key: 'value')
80
+ it 'sets the instance variable without changing builder instance variable' do
81
+ expect { builder.config(key: 'value') }
82
+ .to not_change { builder.instance_variable_get(:@config) }
83
+ .and change(config, :config)
84
+ .from(nil).to(key: 'value')
85
+ end
49
86
  end
50
87
  end
51
88
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::ConfigClass do
6
+ subject(:klass) do
7
+ Class.new { extend Sinclair::ConfigClass }
8
+ end
9
+
10
+ let(:child_klass) { Class.new(klass) }
11
+
12
+ let(:config) { klass.new }
13
+
14
+ describe '.config_attributes' do
15
+ it_behaves_like 'a config class with .config_attributes method'
16
+ end
17
+
18
+ describe '.add_configs' do
19
+ let(:setter_block) do
20
+ proc { |value| config.instance_variable_set(:@name, value) }
21
+ end
22
+
23
+ it_behaves_like 'a config methods builder adding config' do
24
+ let(:code_block) { proc { klass.add_configs(:name) } }
25
+
26
+ it 'sets nil value by default' do
27
+ code_block.call
28
+ expect(config.name).to be_nil
29
+ end
30
+
31
+ it 'adds attributes to class' do
32
+ expect(&code_block).to change(klass, :config_attributes)
33
+ .from([]).to(%i[name])
34
+ end
35
+ end
36
+
37
+ context 'when giving defaults' do
38
+ it_behaves_like 'a config methods builder adding config' do
39
+ let(:code_block) { proc { klass.add_configs(name: 'Bob') } }
40
+
41
+ it 'sets default value' do
42
+ code_block.call
43
+ expect(config.name).to eq('Bob')
44
+ end
45
+
46
+ it 'adds attributes to class' do
47
+ expect(&code_block).to change(klass, :config_attributes)
48
+ .from([]).to(%i[name])
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -28,13 +28,43 @@ describe Sinclair::ConfigFactory do
28
28
  end
29
29
  end
30
30
 
31
- context 'when initializing with custom config class' do
31
+ context 'when initializing with custom config class that extends config_class' do
32
+ subject(:factory) { described_class.new(config_class: MyConfig) }
33
+
34
+ it do
35
+ expect(factory.config).to be_a(MyConfig)
36
+ end
37
+
38
+ context 'when calling after reset_config' do
39
+ before { factory.reset_config }
40
+
41
+ it do
42
+ expect(factory.config).to be_a(MyConfig)
43
+ end
44
+ end
45
+ end
46
+
47
+ context 'when initializing with custom config class that does not extend config_class' do
32
48
  subject(:factory) { described_class.new(config_class: DummyConfig) }
33
49
 
50
+ # rubocop:disable RSpec/AnyInstance
51
+ before do
52
+ allow_any_instance_of(described_class)
53
+ .to receive(:warn)
54
+ end
55
+ # rubocop:enable RSpec/AnyInstance
56
+
34
57
  it do
35
58
  expect(factory.config).to be_a(DummyConfig)
36
59
  end
37
60
 
61
+ it 'warns about class use' do
62
+ factory.config
63
+
64
+ expect(factory).to have_received(:warn)
65
+ .with described_class::CONFIG_CLASS_WARNING
66
+ end
67
+
38
68
  context 'when calling after reset_config' do
39
69
  before { factory.reset_config }
40
70
 
@@ -60,7 +90,7 @@ describe Sinclair::ConfigFactory do
60
90
  end
61
91
 
62
92
  context 'when initializing with custom config class' do
63
- subject(:factory) { described_class.new(config_class: DummyConfig) }
93
+ subject(:factory) { described_class.new(config_class: MyConfig) }
64
94
 
65
95
  it 'reset_configs instance' do
66
96
  expect { factory.reset_config }
@@ -119,6 +149,55 @@ describe Sinclair::ConfigFactory do
119
149
  end
120
150
  end
121
151
  end
152
+
153
+ context 'when config class was set from common class' do
154
+ subject(:factory) { described_class.new(config_class: config_class) }
155
+
156
+ let(:config_class) { Class.new }
157
+
158
+ # rubocop:disable RSpec/AnyInstance
159
+ before do
160
+ allow_any_instance_of(described_class)
161
+ .to receive(:warn)
162
+ end
163
+ # rubocop:enable RSpec/AnyInstance
164
+
165
+ it_behaves_like 'a config factory adding config' do
166
+ let(:method_call) { proc { add_configs(:name) } }
167
+
168
+ it 'does not set a default value' do
169
+ code_block.call
170
+
171
+ expect(factory.config.name).to be_nil
172
+ end
173
+
174
+ it 'warns about class use' do
175
+ code_block.call
176
+
177
+ expect(factory).to have_received(:warn)
178
+ .with described_class::CONFIG_CLASS_WARNING
179
+ end
180
+ end
181
+
182
+ context 'when passing a hash' do
183
+ it_behaves_like 'a config factory adding config' do
184
+ let(:method_call) { proc { add_configs(name: 'Bobby') } }
185
+
186
+ it 'sets a default value' do
187
+ code_block.call
188
+
189
+ expect(factory.config.name).to eq('Bobby')
190
+ end
191
+
192
+ it 'warns about class use' do
193
+ code_block.call
194
+
195
+ expect(factory).to have_received(:warn)
196
+ .with described_class::CONFIG_CLASS_WARNING
197
+ end
198
+ end
199
+ end
200
+ end
122
201
  end
123
202
 
124
203
  describe '#configure' do
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Config do
6
+ subject(:config) { klass.new }
7
+
8
+ let(:child_klass) { Class.new(klass) }
9
+
10
+ let(:klass) { Class.new(described_class) }
11
+
12
+ describe '.config_attributes' do
13
+ it_behaves_like 'a config class with .config_attributes method'
14
+ end
15
+
16
+ describe '#to_hash' do
17
+ it 'returns empty hash' do
18
+ expect(config.as_json).to eq({})
19
+ end
20
+
21
+ context 'when attributes have been defined' do
22
+ before do
23
+ klass.config_attributes(:username, :password)
24
+ klass.attr_reader(:username, :password)
25
+ end
26
+
27
+ it 'uses given attributes to create json' do
28
+ expect(config.as_json)
29
+ .to eq('username' => nil, 'password' => nil)
30
+ end
31
+
32
+ context 'when the method called sets instance variable' do
33
+ before do
34
+ klass.add_configs(name: 'John')
35
+ end
36
+
37
+ it 'returns the value' do
38
+ expect(config.as_json).to eq(
39
+ 'name' => 'John', 'username' => nil, 'password' => nil
40
+ )
41
+ end
42
+ end
43
+ end
44
+
45
+ context 'when passing options' do
46
+ before do
47
+ klass.add_configs(username: 'john', password: '123456')
48
+ end
49
+
50
+ it 'accpes only option' do
51
+ expect(config.as_json(only: 'username'))
52
+ .to eq('username' => 'john')
53
+ end
54
+
55
+ it 'accepts except options' do
56
+ expect(config.as_json(except: 'password'))
57
+ .to eq('username' => 'john')
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '#to_json' do
63
+ it 'returns empty json' do
64
+ expect(config.to_json).to eq('{}')
65
+ end
66
+
67
+ context 'when attributes have been defined' do
68
+ before do
69
+ klass.config_attributes(:username, :password)
70
+ klass.attr_reader(:username, :password)
71
+ end
72
+
73
+ it 'uses given attributes to create json' do
74
+ expect(config.to_json)
75
+ .to eq('{"username":null,"password":null}')
76
+ end
77
+
78
+ context 'when the method called sets instance variable' do
79
+ before do
80
+ klass.add_configs(name: 'John')
81
+ end
82
+
83
+ it 'returns the value' do
84
+ expect(config.to_json).to eq(
85
+ '{"username":null,"password":null,"name":"John"}'
86
+ )
87
+ end
88
+ end
89
+ end
90
+
91
+ context 'when passing options' do
92
+ before do
93
+ klass.add_configs(username: 'john', password: '123456')
94
+ end
95
+
96
+ it 'accpes only option' do
97
+ expect(config.to_json(only: 'username'))
98
+ .to eq('{"username":"john"}')
99
+ end
100
+
101
+ it 'accepts except options' do
102
+ expect(config.to_json(except: 'password'))
103
+ .to eq('{"username":"john"}')
104
+ end
105
+ end
106
+ end
107
+ end
@@ -123,6 +123,14 @@ describe Sinclair::Configurable do
123
123
  end
124
124
  end
125
125
 
126
+ before do
127
+ # rubocop:disable RSpec/SubjectStub
128
+ allow(configurable)
129
+ .to receive(:warn)
130
+ .with(described_class::CONFIG_CLASS_WARNING)
131
+ # rubocop:enable RSpec/SubjectStub
132
+ end
133
+
126
134
  it 'does not add symbol methods config object' do
127
135
  expect(&block)
128
136
  .not_to add_method(:host).to(configurable.config)
@@ -133,6 +141,11 @@ describe Sinclair::Configurable do
133
141
  .not_to add_method(:port).to(configurable.config)
134
142
  end
135
143
 
144
+ it 'sends deprecation warning' do
145
+ block.call
146
+ expect(configurable).to have_received(:warn)
147
+ end
148
+
136
149
  it 'does not raises error on configuration of given symbol attributes' do
137
150
  block.call
138
151
 
@@ -177,6 +190,11 @@ describe Sinclair::Configurable do
177
190
  let(:config_class) { ServerConfig }
178
191
 
179
192
  before do
193
+ # rubocop:disable RSpec/SubjectStub
194
+ allow(configurable)
195
+ .to receive(:warn)
196
+ .with(described_class::CONFIG_CLASS_WARNING)
197
+ # rubocop:enable RSpec/SubjectStub
180
198
  configurable.send(
181
199
  :configurable_by, config_class, with: [:host, 'port']
182
200
  )
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AppConfig
4
+ extend Sinclair::ConfigClass
5
+
6
+ add_configs :secret, app_name: 'MyApp'
7
+ end
@@ -5,5 +5,5 @@ require './spec/support/models/my_server_config'
5
5
  class Client
6
6
  extend Sinclair::Configurable
7
7
 
8
- configurable_by MyServerConfig, with: %i[host port]
8
+ configurable_by MyServerConfig
9
9
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class LoginConfig < Sinclair::Config
4
+ add_configs :password, username: 'bob'
5
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class MyConfig
4
+ extend Sinclair::ConfigClass
5
+
4
6
  attr_reader :name, :config
5
7
  end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class MyServerConfig
3
+ class MyServerConfig < Sinclair::Config
4
+ config_attributes :host, :port
5
+
4
6
  def url
5
7
  if @port
6
8
  "http://#{@host}:#{@port}"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class ServerConfig
3
+ class ServerConfig < Sinclair::Config
4
4
  attr_reader :host, :port
5
5
  end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ shared_examples 'a config class with .config_attributes method' do
4
+ let(:attributes) { [:username, 'password', :key] }
5
+
6
+ describe 'setting the attributes' do
7
+ it 'adds symbol attributes to class attributes' do
8
+ expect { klass.config_attributes(*attributes) }
9
+ .to change(klass, :config_attributes)
10
+ .from([]).to(%i[username password key])
11
+ end
12
+
13
+ context 'when class already has attributes' do
14
+ before do
15
+ klass.config_attributes('email')
16
+ end
17
+
18
+ it 'adds new attributes' do
19
+ expect { klass.config_attributes(*attributes) }
20
+ .to change(klass, :config_attributes)
21
+ .from([:email]).to(%i[email username password key])
22
+ end
23
+ end
24
+
25
+ context 'when attributes have already been added' do
26
+ before do
27
+ klass.config_attributes('username', :password)
28
+ end
29
+
30
+ it 'adds new attributes' do
31
+ expect { klass.config_attributes(*attributes) }
32
+ .to change(klass, :config_attributes)
33
+ .from(%i[username password])
34
+ .to(%i[username password key])
35
+ end
36
+ end
37
+
38
+ context 'when there is a child class' do
39
+ it 'adds attributes to child class' do
40
+ expect { klass.config_attributes(*attributes) }
41
+ .to change(child_klass, :config_attributes)
42
+ .from([]).to(%i[username password key])
43
+ end
44
+
45
+ context 'when child class already has attributes' do
46
+ before do
47
+ child_klass.config_attributes('email')
48
+ end
49
+
50
+ it 'adds new attributes to child class' do
51
+ expect { klass.config_attributes(*attributes) }
52
+ .to change(child_klass, :config_attributes)
53
+ .from([:email]).to(%i[username password key email])
54
+ end
55
+ end
56
+
57
+ context 'when child class already has one of the attributes' do
58
+ before do
59
+ child_klass.config_attributes(:email, 'username')
60
+ end
61
+
62
+ it 'adds new attributes to child class' do
63
+ expect { klass.config_attributes(*attributes) }
64
+ .to change(child_klass, :config_attributes)
65
+ .from(%i[email username]).to(%i[username password key email])
66
+ end
67
+ end
68
+ end
69
+
70
+ context 'when there is a parent class' do
71
+ it 'does not add attributes to parent class' do
72
+ expect { child_klass.config_attributes(*attributes) }
73
+ .not_to change(klass, :config_attributes)
74
+ end
75
+
76
+ context 'when parent already has attributes' do
77
+ before do
78
+ klass.config_attributes(:email, 'username')
79
+ end
80
+
81
+ it 'adds only attributes that had not been defined before' do
82
+ expect { child_klass.config_attributes(*attributes) }
83
+ .to change(child_klass, :config_attributes)
84
+ .from(%i[email username]).to(%i[email username password key])
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ describe 'retrieving the attributes' do
91
+ let(:attributes) { [:username, 'password', :key] }
92
+
93
+ context 'when attributes have been added' do
94
+ before { klass.config_attributes(*attributes) }
95
+
96
+ it 'returns added attributes' do
97
+ expect(klass.config_attributes).to eq(%i[username password key])
98
+ end
99
+ end
100
+
101
+ context 'when parent class has attributes' do
102
+ before { klass.config_attributes(*attributes) }
103
+
104
+ it 'returns parents attributes also' do
105
+ expect(child_klass.config_attributes).to eq(%i[username password key])
106
+ end
107
+ end
108
+
109
+ context 'when parent class changes its attributes' do
110
+ it 'returns adds new attributes to self' do
111
+ expect { klass.config_attributes(*attributes) }
112
+ .to change(child_klass, :config_attributes)
113
+ .from([]).to(%i[username password key])
114
+ end
115
+ end
116
+ end
117
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinclair
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.4
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - DarthJee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-21 00:00:00.000000000 Z
11
+ date: 2019-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -181,15 +181,17 @@ files:
181
181
  - LICENSE
182
182
  - README.md
183
183
  - Rakefile
184
+ - WARNINGS.md
184
185
  - config/rubycritc.rb
185
186
  - config/yardstick.rb
186
187
  - config/yardstick.yml
187
188
  - docker-compose.yml
188
189
  - lib/sinclair.rb
189
190
  - lib/sinclair/config.rb
191
+ - lib/sinclair/config/methods_builder.rb
190
192
  - lib/sinclair/config_builder.rb
193
+ - lib/sinclair/config_class.rb
191
194
  - lib/sinclair/config_factory.rb
192
- - lib/sinclair/config_factory/methods_builder.rb
193
195
  - lib/sinclair/configurable.rb
194
196
  - lib/sinclair/matchers.rb
195
197
  - lib/sinclair/matchers/add_method.rb
@@ -211,7 +213,9 @@ files:
211
213
  - spec/integration/sinclair/matchers_spec.rb
212
214
  - spec/integration/yard/my_builder_spec.rb
213
215
  - spec/integration/yard/sinclair/config_builder_spec.rb
216
+ - spec/integration/yard/sinclair/config_class_spec.rb
214
217
  - spec/integration/yard/sinclair/config_factory_spec.rb
218
+ - spec/integration/yard/sinclair/config_spec.rb
215
219
  - spec/integration/yard/sinclair/configurable_spec.rb
216
220
  - spec/integration/yard/sinclair/matchers/add_method_spec.rb
217
221
  - spec/integration/yard/sinclair/matchers/add_method_to_spec.rb
@@ -220,9 +224,11 @@ files:
220
224
  - spec/integration/yard/sinclair/method_definition_spec.rb
221
225
  - spec/integration/yard/sinclair/options_parser_spec.rb
222
226
  - spec/integration/yard/sinclair_spec.rb
227
+ - spec/lib/sinclair/config/methods_builder_spec.rb
223
228
  - spec/lib/sinclair/config_builder_spec.rb
224
- - spec/lib/sinclair/config_factory/methods_builder_spec.rb
229
+ - spec/lib/sinclair/config_class_spec.rb
225
230
  - spec/lib/sinclair/config_factory_spec.rb
231
+ - spec/lib/sinclair/config_spec.rb
226
232
  - spec/lib/sinclair/configurable_spec.rb
227
233
  - spec/lib/sinclair/matchers/add_method_spec.rb
228
234
  - spec/lib/sinclair/matchers/add_method_to_spec.rb
@@ -234,6 +240,7 @@ files:
234
240
  - spec/lib/sinclair_spec.rb
235
241
  - spec/spec_helper.rb
236
242
  - spec/support/fixture_helpers.rb
243
+ - spec/support/models/app_config.rb
237
244
  - spec/support/models/client.rb
238
245
  - spec/support/models/default_value.rb
239
246
  - spec/support/models/default_value_builder.rb
@@ -245,6 +252,7 @@ files:
245
252
  - spec/support/models/http_json_model.rb
246
253
  - spec/support/models/http_person.rb
247
254
  - spec/support/models/initial_valuer.rb
255
+ - spec/support/models/login_config.rb
248
256
  - spec/support/models/my_builder.rb
249
257
  - spec/support/models/my_class.rb
250
258
  - spec/support/models/my_concern.rb
@@ -257,6 +265,7 @@ files:
257
265
  - spec/support/models/server.rb
258
266
  - spec/support/models/server_config.rb
259
267
  - spec/support/models/validator_builder.rb
268
+ - spec/support/shared_examples/config.rb
260
269
  - spec/support/shared_examples/config_factory.rb
261
270
  - spec/support/shared_examples/method_definition.rb
262
271
  homepage: https://github.com/darthjee/sinclair