confo-config 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e18009a32d37da15b10c87cff286b37be9ff6a2e
4
- data.tar.gz: 0e2ad064b148ef7237ec98722afebb703dd8b2bb
3
+ metadata.gz: 710b4899fb2c7ff8bb1fe82afdb2ecc5dae2e3ed
4
+ data.tar.gz: 85ee34a5653d81be7fa89834d770e4778081581e
5
5
  SHA512:
6
- metadata.gz: f759fb4b9277b5f78c559cda2e270d97d2741827f2536e3cb40578d97f902eda3eaceac0906bcef6cc0b898fda0fdf1f0f105712d5fcd1570342d67eb453c548
7
- data.tar.gz: d05dbef7d09242b374b5872202349dd315c7899302554e08dd143db3c30b55a5f26f7446d50e588df09bf43aebb69be38425ac63648a44debfec0f8e7cc475ae
6
+ metadata.gz: 9415241fcf386be99983cfa849bc4e1ef8549fddae646e560262c78bcaf3d643cf6b49abaf8a6abd2188cf52a0e8e828bdb15e3861da04f3ac4b5138f0fa9920
7
+ data.tar.gz: 37e68f2e2893d3503b5bfc0d380bdbda569b4199ead0a783c0c1b07eded895de10f9d1a879a3cc2c323f5ef615c97ffea6a8cbb7c501946defcee2295939d4b2
@@ -1,19 +1,20 @@
1
+ # encoding: utf-8
1
2
  require File.expand_path('../lib/confo/version', __FILE__)
2
3
 
3
- Gem::Specification.new do |spec|
4
- spec.name = 'confo-config'
5
- spec.version = Confo::VERSION
6
- spec.authors = ['Yaroslav Konoplov']
7
- spec.email = ['yaroslav@inbox.com']
8
- spec.summary = 'Little configuration framework'
9
- spec.description = 'Little configuration framework'
10
- spec.homepage = 'http://github.com/yivo/confo-config'
11
- spec.license = 'MIT'
4
+ Gem::Specification.new do |s|
5
+ s.name = 'confo-config'
6
+ s.version = Confo::VERSION
7
+ s.authors = ['Yaroslav Konoplov']
8
+ s.email = ['yaroslav@inbox.com']
9
+ s.summary = 'Little configuration framework'
10
+ s.description = 'Little configuration framework'
11
+ s.homepage = 'http://github.com/yivo/confo-config'
12
+ s.license = 'MIT'
12
13
 
13
- spec.files = `git ls-files -z`.split("\x0")
14
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
16
- spec.require_paths = ['lib']
14
+ s.executables = `git ls-files -z -- bin/*`.split("\x0").map{ |f| File.basename(f) }
15
+ s.files = `git ls-files -z`.split("\x0")
16
+ s.test_files = `git ls-files -z -- {test,spec,features}/*`.split("\x0")
17
+ s.require_paths = ['lib']
17
18
 
18
- spec.add_dependency 'activesupport', '~> 4.0' # 4.0 <= version < 5.0
19
- end
19
+ s.add_dependency 'activesupport', '>= 3.2.0'
20
+ end
@@ -22,12 +22,12 @@ module Confo
22
22
  end
23
23
 
24
24
  def convert_to_hash(value)
25
- if value.is_a?(Hash)
25
+ if value.respond_to?(:to_hash)
26
26
  value.to_hash
27
27
  elsif value.is_a?(Array)
28
28
  value.map { |e| convert_to_hash(e) }
29
29
  else
30
- value.respond_to?(:to_hash) ? value.to_hash : value
30
+ value
31
31
  end
32
32
  end
33
33
 
@@ -2,10 +2,10 @@ module Confo
2
2
  class Collection
3
3
  include Enumerable
4
4
 
5
- attr_reader :behaviour_options
5
+ attr_reader :settings
6
6
 
7
- def initialize(behaviour_options = {}, &block)
8
- @behaviour_options = behaviour_options
7
+ def initialize(settings = {}, &block)
8
+ @settings = settings
9
9
  configure(&block) if block
10
10
  end
11
11
 
@@ -14,19 +14,22 @@ module Confo
14
14
  config = storage[id]
15
15
  config ||= begin
16
16
  config_class = Confo.call(self, :config_class, id, construct_options)
17
+ check_config_class!(config_class)
17
18
  config = Confo.call(self, :construct_config, config_class, id, construct_options)
18
19
  storage[id] = config
19
20
  config.set(:name, id)
20
21
  config
21
22
  end
22
23
 
23
- config.set(options) if options
24
+ config.set(options) if options && config.kind_of?(Config)
24
25
  config.configure(&block) if block
25
26
  config
26
27
  end
27
28
 
28
29
  def get(id)
30
+ id = convert_id(id)
29
31
  define(id)
32
+ storage[id]
30
33
  end
31
34
 
32
35
  def set(id, config)
@@ -49,23 +52,52 @@ module Confo
49
52
  end
50
53
 
51
54
  def to_a
52
- storage.values
55
+ storage.each_with_object([]) do |(id, instance), memo|
56
+ memo << (instance.respond_to?(:to_hash) ? instance.to_hash : instance)
57
+ end
53
58
  end
54
59
 
55
60
  def to_hash
56
- storage.reduce({}) do |memo, (id, instance)|
61
+ storage.each_with_object({}) do |(id, instance), memo|
57
62
  memo[id] = Confo.convert_to_hash(instance)
58
- memo
59
63
  end
60
64
  end
61
65
 
62
- protected
66
+ def method_missing(name, *args, &block)
67
+ if args.empty? && name =~ /^(\w+)\?$/
68
+ exists?($1)
69
+ else
70
+ super
71
+ end
72
+ end
73
+
74
+ def with_new_settings(new_settings)
75
+ self.class.new(settings.merge(new_settings)).tap do |new_obj|
76
+ if storage = @storage
77
+ storage.each { |k, v| new_obj.set(k, v.with_new_settings(new_settings) ) }
78
+ end
79
+ end
80
+ end
81
+
82
+ def dup(config_settings = {})
83
+ self.class.new(settings.merge(config_settings)).tap do |new_obj|
84
+ if storage = @storage
85
+ new_obj.instance_variable_set(:@storage, storage)
86
+ end
87
+ end
88
+ end
89
+
90
+ def deep_dup(config_settings = {})
91
+ with_new_settings(config_settings)
92
+ end
93
+
94
+ protected
63
95
 
64
96
  def config_class(config_id, config_options)
65
97
  config_options.try(:[], :class_name).try(:safe_constantize) || Config
66
98
  end
67
99
 
68
- def construct_config(config_class)
100
+ def construct_config(config_class, config_id, construct_options)
69
101
  config_class.new
70
102
  end
71
103
 
@@ -74,7 +106,11 @@ module Confo
74
106
  end
75
107
 
76
108
  def convert_id(id)
77
- id.to_sym
109
+ id.kind_of?(Symbol) ? id : id.to_sym
110
+ end
111
+
112
+ def check_config_class!(config_class)
113
+ raise 'Forbidden config class!' unless (config_class <= Config or config_class <= Collection)
78
114
  end
79
115
  end
80
116
  end
@@ -6,12 +6,20 @@ module Confo
6
6
 
7
7
  # Define option accessors.
8
8
  def option_accessor(*names)
9
+
10
+ # TODO Save list of option names
9
11
  names.each do |name|
10
12
  define_option_functional_accessor(name)
11
13
  define_option_writer(name)
12
14
  end
13
15
  end
14
16
 
17
+ # TODO Implement
18
+ def readonly_option(*names)
19
+
20
+ end
21
+
22
+ protected
15
23
  def define_option_functional_accessor(name)
16
24
  define_method("#{name}") do |*args|
17
25
  if args.size > 0
@@ -47,12 +55,13 @@ module Confo
47
55
  # Alias for +get+.
48
56
  alias [] get
49
57
 
50
- protected
58
+ protected
51
59
 
52
60
  # Method to get an option.
53
61
  # If there is an option accessor defined then it will be used.
54
62
  # In other cases +raw_get+ will be used.
55
63
  def public_get(option)
64
+ # TODO Prevent subconfigs here
56
65
  respond_to?(option) ? send(option) : raw_get(option)
57
66
  end
58
67
 
@@ -60,11 +69,11 @@ module Confo
60
69
  # If value is callable without arguments
61
70
  # it will be called and result will be returned.
62
71
  def raw_get(option)
63
- value = storage[option]
72
+ value = options_storage[option]
64
73
  Confo.callable_without_arguments?(value) ? value.call : value
65
74
  end
66
75
 
67
- public
76
+ public
68
77
 
69
78
  # Sets option:
70
79
  # obj.set(:option, 'value')
@@ -82,22 +91,23 @@ module Confo
82
91
  # Alias for +set+.
83
92
  alias []= set
84
93
 
85
- protected
94
+ protected
86
95
 
87
96
  # Method to set an option.
88
97
  # If there is an option accessor defined then it will be used.
89
98
  # In other cases +raw_set+ will be used.
90
99
  def public_set(option, value)
100
+ # TODO Prevent subconfigs here
91
101
  method = "#{option}="
92
102
  respond_to?(method) ? send(method, value) : raw_set(option, value)
93
103
  end
94
104
 
95
105
  # Internal method to set option.
96
106
  def raw_set(option, value)
97
- storage[option] = value
107
+ options_storage[option] = value
98
108
  end
99
109
 
100
- public
110
+ public
101
111
 
102
112
  # Sets option only if it is not set yet:
103
113
  # obj.set_at_first(:option, 1)
@@ -129,7 +139,7 @@ module Confo
129
139
  set(arg, rest_args.first) unless set?(arg)
130
140
  true
131
141
  else
132
- storage.has_key?(arg)
142
+ options_storage.has_key?(arg)
133
143
  end
134
144
  end
135
145
 
@@ -142,43 +152,38 @@ module Confo
142
152
 
143
153
  # Unsets option.
144
154
  def unset(option)
145
- storage.delete(option)
155
+ options_storage.delete(option)
146
156
  self
147
157
  end
148
158
 
149
159
  # Returns option names as array of symbols.
150
160
  def keys
151
- storage.reduce([]) do |memo, k, v|
161
+ options_storage.each_with_object([]) do |(k, v), memo|
152
162
  memo << k.to_sym
153
- memo
154
163
  end
155
164
  end
156
165
 
157
166
  # Returns option values as array.
158
167
  def values
159
- storage.values
168
+ options_storage.each_with_object([]) do |(k, v), memo|
169
+ memo << get(k)
170
+ end
160
171
  end
161
172
 
162
173
  # Returns all options at once.
163
174
  # obj.options => { option: 'value' }
164
175
  def options
165
- options = storage.dup
166
- options.each { |k, v| options[k] = get(k) }
167
- options
176
+ options_storage.each_with_object({}) do |(k, v), memo|
177
+ memo[k.to_sym] = get(k)
178
+ end
168
179
  end
169
180
 
170
- protected
171
-
172
- def storage
173
- @storage ||= OptionsStorage.new
181
+ protected
182
+ def options_storage
183
+ @options_storage ||= OptionsStorage.new
174
184
  end
175
185
  end
176
186
 
177
- class OptionsStorage < Hash
178
- def to_hash
179
- new_hash = {}
180
- each { |k, v| new_hash[k.kind_of?(String) ? k.to_sym : k] = Confo.convert_to_hash(v) }
181
- Hash.new(default).merge!(new_hash)
182
- end
187
+ class OptionsStorage < ActiveSupport::HashWithIndifferentAccess
183
188
  end
184
189
  end
@@ -59,7 +59,7 @@ module Confo
59
59
  subconfig_instances.exists?(subconfig_name)
60
60
  end
61
61
 
62
- protected
62
+ protected
63
63
 
64
64
  def subconfig_instances
65
65
  @subconfig_instances ||= Collection.new
@@ -67,6 +67,8 @@ module Confo
67
67
 
68
68
  def subconfig_internal(subconfig_name, options = nil, overrides = nil, &block)
69
69
  unless subconfig_exists?(subconfig_name)
70
+
71
+ # TODO Bugfix
70
72
  subconfig_options = self.class.subconfigs_options[subconfig_name].try(:dup) || {}
71
73
  subconfig_options.merge!(overrides) if overrides
72
74
 
@@ -88,7 +90,7 @@ module Confo
88
90
 
89
91
  def subconfig_class(subconfig_name, subconfig_options)
90
92
  if class_name = subconfig_options[:class_name]
91
- class_name.to_s.camelize
93
+ class_name.camelize
92
94
  else
93
95
  guess_subconfig_class_name(subconfig_name)
94
96
  end.safe_constantize || subconfig_options.fetch(:fallback_class_name, 'Confo::Config').constantize
@@ -5,14 +5,42 @@ module Confo
5
5
  include OptionsManager
6
6
  include SubconfigsManager
7
7
 
8
- attr_reader :behaviour_options
8
+ attr_reader :settings
9
9
 
10
- def initialize(behaviour_options = {}, &block)
11
- @behaviour_options = behaviour_options
10
+ def initialize(settings = {}, &block)
11
+ @settings = settings
12
12
  preconfigure
13
13
  configure(&block) if block
14
14
  end
15
15
 
16
+ def with_new_settings(new_settings)
17
+ self.class.new(settings.merge(new_settings)).tap do |new_config|
18
+ if var = @options_storage
19
+ new_config.instance_variable_set(:@options_storage, var.deep_dup)
20
+ end
21
+
22
+ if var = @subconfig_instances
23
+ new_config.instance_variable_set(:@subconfig_instances, var.with_new_settings(new_settings))
24
+ end
25
+ end
26
+ end
27
+
28
+ def dup(config_settings = {})
29
+ self.class.new(settings.merge(config_settings)).tap do |new_config|
30
+ if var = @options_storage
31
+ new_config.instance_variable_set(:@options_storage, var)
32
+ end
33
+
34
+ if var = @subconfig_instances
35
+ new_config.instance_variable_set(:@subconfig_instances, var)
36
+ end
37
+ end
38
+ end
39
+
40
+ def deep_dup(config_settings = {})
41
+ with_new_settings(config_settings)
42
+ end
43
+
16
44
  def configure(*args, &block)
17
45
  case args.size
18
46
 
@@ -58,39 +86,49 @@ module Confo
58
86
  # Wants to configure subconfig:
59
87
  # object.description { }
60
88
  subconfig(name, &block)
61
- else
62
89
 
90
+ # Wants to access boolean option:
91
+ # object.property?
92
+ elsif name =~ /^(\w+)\?$/
93
+ !!get($1)
94
+
95
+ else
63
96
  # Wants one of the following:
64
97
  # - access subconfig
65
98
  # - access option
66
- subconfig_exists?(name) ? subconfig(name) : option(normalize_option(name))
99
+ subconfig_exists?(name) ? subconfig(name) : option(strip_assignment(name))
67
100
  end
68
101
 
69
102
  when 1
70
103
  arg = args.first
71
104
 
105
+ # Wants to test option value:
106
+ # object.property?(:value) => options[:property] == :value
107
+ if name =~ /^(\w+)\?$/
108
+ get($1) == arg
109
+
72
110
  # Wants to access collection:
73
111
  # object.properties :id { }
74
- if (arg.is_a?(String) || arg.is_a?(Symbol)) && subconfig_exists?(name)
112
+ elsif (arg.is_a?(String) || arg.is_a?(Symbol)) && subconfig_exists?(name)
75
113
  subconfig(name.to_s.pluralize, arg, &block)
76
- else
77
114
 
115
+ else
78
116
  # Wants to access option:
79
117
  # object.cache = :none
80
118
  # object.cache :none
81
- option(normalize_option(name), arg)
119
+ option(strip_assignment(name), arg)
82
120
  end
83
121
 
84
122
  else
85
- option(normalize_option(name), *args)
123
+ option(strip_assignment(name), *args)
86
124
  end
87
125
  end
88
126
 
89
127
  def to_hash
90
- {}.merge!(options.to_hash).merge!(subconfigs.to_hash)
128
+ options.merge!(subconfigs).to_hash
91
129
  end
92
130
 
93
- protected
131
+ protected
94
132
 
95
133
  def preconfigure
96
134
  preconfigurator_class = lookup_preconfigurator_class
@@ -114,7 +152,7 @@ module Confo
114
152
  "#{configurable_component_name}Preconfigurator"
115
153
  end
116
154
 
117
- def normalize_option(name)
155
+ def strip_assignment(name)
118
156
  name.to_s.sub(/=+\Z/, '').to_sym
119
157
  end
120
158
  end
@@ -1,3 +1,3 @@
1
1
  module Confo
2
- VERSION = '1.0.0'
2
+ VERSION = '1.0.1'
3
3
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: confo-config
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yaroslav Konoplov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-04 00:00:00.000000000 Z
11
+ date: 2015-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.0'
19
+ version: 3.2.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '4.0'
26
+ version: 3.2.0
27
27
  description: Little configuration framework
28
28
  email:
29
29
  - yaroslav@inbox.com