config_plus 0.0.5 → 0.0.7

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
  SHA1:
3
- metadata.gz: 189eb84bec6ebcfa3fbb181d5d548c47fb7e4c3e
4
- data.tar.gz: 8b71d5dc1ac70f6eadc0fe5d49d78e724d63ad6c
3
+ metadata.gz: e208952531353609f29e28211515eb3b11bf0781
4
+ data.tar.gz: 76453e257d4804a459336cd536d5a0ba5654ae48
5
5
  SHA512:
6
- metadata.gz: 4c5807c8460291543b7c536d0394034b05cc3bdef580fddccf312f56ee7af0fd69f78a3481f661e131263b9b5eae7c3141c0c55006f10c682b19a2a807d897cc
7
- data.tar.gz: 7ccf3c2d162116d904e5d56162461cfc1f311239af62158869efbeb25d6df09a72b3035bd2797eebb0d005657829a56e9eadaca6a7c506d3580b1cdb5b6bd754
6
+ metadata.gz: eea53a7069d354366b6bf0e9f6155736514459c0fe8e1dab6178a0d3f70500f33539f8a7b63f57b551ae3ab40622ec1d0ccc7e66938edaa95a5001d0216b7a07
7
+ data.tar.gz: 53697c89a5c3400e9d3e9179e67d78f4021a04160a647c00afe4a84afbbb9e1238d51736f99deb9e9ea3350f15a56e740ea06938397d2114b58b733834e4c41e
@@ -141,6 +141,30 @@ Sample::SettingA.config
141
141
  #=> {"spam"=>"bacon", "ham"=>"spam", "egg"=>"baked beans"}
142
142
  ```
143
143
 
144
+ 個別ロード
145
+ --------------------------------------------------
146
+ `ConfigPlus` の基本動作では、指定された設定ファイル群の情報を `ConfigPlus.root`
147
+ に読み込みます。つまり、すべての情報は基本的にひとつのオプジェクトで管理されます。
148
+
149
+ これはシンプルな方法ですが、個別に読み込み、管理したいということもあるかもしれません。
150
+ 次のようにすると、個別に設定情報を持たせることができます。
151
+
152
+ ```ruby
153
+ class Foo
154
+ extend ConfigPlus::Single
155
+ generate_config '/path/to/configuration/file.yml', as: :conf
156
+ end
157
+
158
+ Foo.conf[:foo]
159
+ # => foo の値
160
+
161
+ ConfigPlus.root
162
+ # => nil
163
+ ```
164
+
165
+ オプションの `as` で設定情報にアクセスするメソッド名を指定できます。
166
+ 省略すると `config` が使われます。
167
+
144
168
  その他
145
169
  --------------------------------------------------
146
170
  `ConfigPlus` の動作は設定で変更できます。
data/README.md CHANGED
@@ -126,6 +126,29 @@ Sample::SettingA.config
126
126
  #=> {"spam"=>"bacon", "ham"=>"spam", "egg"=>"baked beans"}
127
127
  ```
128
128
 
129
+ Load Individually
130
+ ------------------------------------------------------------
131
+ Basically, `ConfigPlus` loads the specified configuration files
132
+ and merges all of the data into a single hash `ConfigPlus.root`.
133
+
134
+ But if you want to get the data in an other hash, you can do by
135
+ the following way:
136
+
137
+ ```ruby
138
+ class Foo
139
+ extend ConfigPlus::Single
140
+ generate_config '/path/to/configuration/file.yml', as: :conf
141
+ end
142
+
143
+ Foo.conf[:foo]
144
+ # => a value of `foo'
145
+
146
+ ConfigPlus.root
147
+ # => nil
148
+ ```
149
+
150
+ You can specify the method name for access to configuration data
151
+ by the option `as`, which default value is `config`.
129
152
 
130
153
  Others
131
154
  ------------------------------------------------------------
@@ -1,7 +1,8 @@
1
- require 'config_plus/base'
2
1
  require 'config_plus/version'
3
2
 
4
3
  module ConfigPlus
4
+ autoload :Base, 'config_plus/base'
5
+ autoload :Collection, 'config_plus/collection'
5
6
  autoload :Config, 'config_plus/config'
6
7
  autoload :DefaultLoaderLogic, 'config_plus/default_loader_logic'
7
8
  autoload :ErbYamlLoaderLogic, 'config_plus/erb_yaml_loader_logic'
@@ -9,4 +10,7 @@ module ConfigPlus
9
10
  autoload :Loader, 'config_plus/loader'
10
11
  autoload :Merger, 'config_plus/merger'
11
12
  autoload :Node, 'config_plus/node'
13
+ autoload :Single, 'config_plus/single'
14
+
15
+ extend Base
12
16
  end
@@ -1,5 +1,5 @@
1
1
  module ConfigPlus
2
- class << self
2
+ module Base
3
3
  attr_reader :root
4
4
 
5
5
  # Sets up configuration of ++ConfigPlus++ and loads data
@@ -28,7 +28,7 @@ module ConfigPlus
28
28
  # ConfigPlus.generate(from: '/path/to/yaml/file.yml')
29
29
  #
30
30
  def generate(options={})
31
- config.source = options.delete(:from) or options.delete('from')
31
+ config.source = options.delete(:from) || options.delete('from')
32
32
  options.each do |k, v|
33
33
  if config.has_property?(k)
34
34
  config.property_set(k, v)
@@ -39,16 +39,38 @@ module ConfigPlus
39
39
  load
40
40
  end
41
41
 
42
+ def single_generate(source, options={})
43
+ meth = [:as, :config_method].lazy.map {|nm|
44
+ options.delete(nm) || options.delete(nm.to_s)
45
+ }.find {|v| v } || :config
46
+ klass = options.delete(:to) || options.delete('to')
47
+ raise unless klass
48
+
49
+ conf = self::Config.new
50
+ conf.source = source
51
+ options.each do |k, v|
52
+ conf.has_property?(k) and conf.property_set(k, v) or
53
+ raise "Unknown configuration property `#{k}'"
54
+ end
55
+
56
+ hsh = conf.loader.load
57
+ conf.node_model.new(hsh).tap do |tree|
58
+ [klass.singleton_class, klass].each do |obj|
59
+ obj.instance_eval { define_method meth, lambda { tree } }
60
+ end
61
+ end
62
+ end
63
+
42
64
  protected
43
65
 
44
66
  def config
45
- @config ||= self::Config.new
67
+ @config ||= ::ConfigPlus::Config.new
46
68
  end
47
69
 
48
70
  private
49
71
 
50
72
  # Loads a configuration data as a hash object
51
- # from files specified with ++source++ or
73
+ # from files specified with ++source++ or
52
74
  # ++root_dir++ settings.
53
75
  #
54
76
  def load
@@ -63,23 +85,23 @@ module ConfigPlus
63
85
  clazz.ancestors.include?(self)
64
86
  }.reverse.each.inject({}) {|hsh, clazz|
65
87
  h = clazz.public_send(self.config.config_method)
66
- h = self::Helper.config_for(clazz, self.root) unless
88
+ h = ::ConfigPlus::Helper.config_for(clazz, self.root) unless
67
89
  h or h.is_a?(Hash)
68
- self::Merger.merge(hsh, h)
90
+ ::ConfigPlus::Merger.merge(hsh, h)
69
91
  }
70
92
  end
71
93
 
72
94
  def included(base)
73
95
  method_name = self.config.config_method
74
96
  return unless method_name
75
- own = self::Helper.config_for(base, self.root)
97
+ own = ::ConfigPlus::Helper.config_for(base, self.root)
76
98
  inheritance = inherited_config_of(base)
77
99
 
78
100
  node_model = config.node_model
79
101
  [base, base.singleton_class].each do |obj|
80
102
  obj.instance_eval do
81
- config = inheritance ?
82
- ::ConfigPlus::Merger.merge(inheritance, own || {}) : own
103
+ config = inheritance.empty? ? own :
104
+ ::ConfigPlus::Merger.merge(inheritance, own || {})
83
105
  config = node_model.new(config)
84
106
  define_method method_name, lambda { config }
85
107
  end
@@ -0,0 +1,193 @@
1
+ require 'forwardable'
2
+
3
+ module ConfigPlus
4
+ class Collection
5
+ extend Forwardable
6
+
7
+ def_delegators :data,
8
+ :each,
9
+ :include?,
10
+ :inspect,
11
+ :size,
12
+ :to_a,
13
+ :to_s,
14
+ :values_at
15
+
16
+ def initialize(collection)
17
+ @hash_data = nil
18
+ @array_data = nil
19
+ data = retrieve_data_out_of(collection)
20
+
21
+ case data
22
+ when Hash
23
+ @hash_data = {}
24
+ when Array
25
+ @array_data = []
26
+ else
27
+ raise TypeError, "An argument should be Hash or Array " \
28
+ "but #{collection.class.name}"
29
+ end
30
+ end
31
+
32
+ def [](key)
33
+ self.fetch(key, nil)
34
+ end
35
+
36
+ def fetch(*arguments)
37
+ raise ArgumentError if arguments.size > 2 or arguments.empty?
38
+ args = arguments.dup
39
+ args[0] = args[0].to_s
40
+
41
+ if array? and args[0] =~ /\A\d+\z/
42
+ args[0] = args[0].to_i
43
+ data.fetch(*args)
44
+ elsif hash?
45
+ v = data.fetch(*args)
46
+ if !v and args[0] =~ /\A\d+\z/
47
+ args[0] = args[0].to_i
48
+ v = data.fetch(*args)
49
+ end
50
+ v
51
+ else
52
+ raise
53
+ end
54
+ end
55
+
56
+ def merge(collection)
57
+ raise TypeError, "An argument should be an instance of #{data.class.name}" \
58
+ " but #{collection.class.name}" if
59
+ self.miss_match?(collection)
60
+ data = retrieve_data_out_of collection
61
+
62
+ if hash?
63
+ hash_data.merge(data)
64
+ else
65
+ array_data + data
66
+ end
67
+ end
68
+
69
+ def merge!(collection)
70
+ raise TypeError, "An argument should be an instance of #{data.class.name}" \
71
+ " but #{collection.class.name}" if
72
+ self.miss_match?(collection)
73
+ data = retrieve_data_out_of collection
74
+
75
+ if hash?
76
+ hash_data.merge!(data)
77
+ else
78
+ array_data.concat(data)
79
+ end
80
+ end
81
+
82
+ def each_key
83
+ if hash?
84
+ hash_data.each_key
85
+ else
86
+ (0...array_data.size).each
87
+ end
88
+ end
89
+
90
+ def each_pair
91
+ if hash?
92
+ hash_data.each_pair
93
+ else
94
+ array_data.lazy.with_index.map {|v, n|
95
+ [n, v]
96
+ }.each
97
+ end
98
+ end
99
+
100
+ def keys
101
+ if hash?
102
+ hash_data.keys
103
+ else
104
+ Array.new(array_data, &:to_i)
105
+ end
106
+ end
107
+
108
+ def key?(val)
109
+ if hash?
110
+ hash_data.key?(val.to_s)
111
+ elsif val.to_s =~ /\A\d+\z/
112
+ val.to_i.between?(0, array_data.size - 1)
113
+ else
114
+ false
115
+ end
116
+ end
117
+ alias :has_key? :key?
118
+
119
+ def store(key, val)
120
+ if hash?
121
+ hash_data.store(key.to_s, val)
122
+ elsif key.to_s =~ /\A\d+\z/
123
+ array_data[key.to_i] = val
124
+ end
125
+ end
126
+
127
+ def to_hash
128
+ if hash?
129
+ hash_data.to_hash
130
+ else
131
+ Hash.try_convert(data)
132
+ end
133
+ end
134
+
135
+ def value?(val)
136
+ if hash?
137
+ hash_data.value?(val)
138
+ else
139
+ array_data.include?(val)
140
+ end
141
+ end
142
+ alias :has_value? :value?
143
+
144
+ def values
145
+ if hash?
146
+ hash_data.values
147
+ else
148
+ array_data
149
+ end
150
+ end
151
+
152
+ def data
153
+ hash_data || array_data
154
+ end
155
+
156
+ def hash?
157
+ !!hash_data
158
+ end
159
+
160
+ def array?
161
+ !!array_data
162
+ end
163
+
164
+ protected
165
+
166
+ def miss_match?(collection)
167
+ data.class != collection.class && !collection.is_a?(self.class)
168
+ end
169
+
170
+ private
171
+
172
+ attr_reader :hash_data, :array_data
173
+
174
+ def retrieve_data_out_of(object)
175
+ case object
176
+ when Hash, Array
177
+ object
178
+ when self.class
179
+ object.data
180
+ else
181
+ raise TypeError, "#{object.class.name} could not be acceptable"
182
+ end
183
+ end
184
+
185
+ class << self
186
+ def generate_for(collection)
187
+ new(collection)
188
+ end
189
+
190
+ private :new
191
+ end
192
+ end
193
+ end
@@ -1,39 +1,32 @@
1
1
  module ConfigPlus
2
+ # Configuration of ConfigPlus
2
3
  class Config
3
- class << self
4
- attr_reader :properties
5
-
6
- def prop_accessor(*names)
7
- @properties ||= []
8
- @properties.concat(names)
9
- attr_accessor *names
10
- end
11
-
12
- private :prop_accessor
4
+ def self.default_properties
5
+ {
6
+ config_method: :config,
7
+ extension: nil,
8
+ namespace: nil,
9
+ node_model: Node,
10
+ root_dir: nil,
11
+ source: nil,
12
+ loader_logic: :default,
13
+ }
13
14
  end
14
15
 
15
- prop_accessor :config_method,
16
- :extension,
17
- :namespace,
18
- :node_model,
19
- :root_dir,
20
- :source,
21
- :loader_logic
22
-
23
16
  def initialize
24
- @config_method = :config
25
- @extension = nil
26
- @loader_logic = :default
27
- @namespace = nil
28
- @node_model = Node
29
- @root_dir = nil
30
- @source = nil
17
+ props = self.class.default_properties.each do |k, v|
18
+ instance_variable_set("@#{k}", v)
19
+ end
20
+
21
+ setup_attrs(props.keys)
31
22
  end
32
23
 
24
+ # returns a new loader instance
33
25
  def loader
34
26
  Loader.new(self)
35
27
  end
36
28
 
29
+ # returns loader class specified by +loader_logic+ property
37
30
  def loader_logic
38
31
  return @loader_logic if @loader_logic.is_a?(Class)
39
32
 
@@ -49,11 +42,20 @@ module ConfigPlus
49
42
  end
50
43
 
51
44
  def has_property?(name)
52
- self.class.properties.include?(name.to_sym)
45
+ instance_variable_defined?("@#{name}")
53
46
  end
54
47
 
55
48
  def property_set(name, value)
56
49
  instance_variable_set("@#{name}", value)
57
50
  end
51
+
52
+ private
53
+
54
+ def setup_attrs(attr_names)
55
+ singleton_class.instance_eval do
56
+ attr_writer *attr_names
57
+ attr_reader *(attr_names - instance_methods)
58
+ end
59
+ end
58
60
  end
59
61
  end
@@ -31,6 +31,8 @@ module ConfigPlus
31
31
 
32
32
  private
33
33
 
34
+ # Finds parts of data that match with a name of the specified object
35
+ #
34
36
  def matched_configs(object, node)
35
37
  return [] unless node
36
38
  mod = object.is_a?(Module) ? object : object.class
@@ -8,9 +8,9 @@ module ConfigPlus
8
8
  paths = source_paths
9
9
  raise "No specified `source'" if paths.empty?
10
10
 
11
- paths.each.inject({}) do |h, path|
11
+ paths.inject({}) do |h, path|
12
12
  hsh = loader_logic.load_from(path)
13
- hsh = hsh[@config.namespace.to_s] if @config.namespace
13
+ hsh = hsh[config.namespace.to_s] if config.namespace
14
14
  Merger.merge(h, hsh)
15
15
  end
16
16
  end
@@ -18,20 +18,24 @@ module ConfigPlus
18
18
  protected
19
19
 
20
20
  def loader_logic
21
- @loader_logic ||= @config.loader_logic.new(@config.extension)
21
+ @loader_logic ||= config.loader_logic.new(config.extension)
22
22
  end
23
23
 
24
24
  def source_paths
25
- Array(@config.source).map {|s|
25
+ Array(config.source).map {|s|
26
26
  source_path(s)
27
27
  }.reverse.uniq.compact.reverse
28
28
  end
29
29
 
30
30
  def source_path(filepath)
31
- return filepath unless @config.root_dir
32
- return @config.root_dir unless filepath
31
+ return filepath unless config.root_dir
32
+ return config.root_dir unless filepath
33
33
  return filepath if filepath.start_with?('/')
34
- File.join(@config.root_dir, filepath)
34
+ File.join(config.root_dir, filepath)
35
35
  end
36
+
37
+ private
38
+
39
+ attr_reader :config
36
40
  end
37
41
  end
@@ -15,8 +15,12 @@ module ConfigPlus
15
15
  if collection1.is_a?(Array) and
16
16
  collection2.is_a?(Array)
17
17
  collection1.concat(collection2)
18
+ elsif collection2.is_a?(::ConfigPlus::Node)
19
+ collection1.merge(collection2.__send__(:node), &MERGER)
18
20
  else
19
- collection1.merge(collection2, &MERGER)
21
+ object = collection2.__send__(:node) if collection2.is_a?(::ConfigPlus::Node)
22
+ object ||= collection2
23
+ collection1.merge(object, &MERGER)
20
24
  end
21
25
  end
22
26
  end
@@ -1,18 +1,42 @@
1
+ require 'forwardable'
2
+
1
3
  module ConfigPlus
2
- class Node < Hash
3
- def initialize(hash = nil)
4
- node = super()
5
- node.merge!(hash) if hash
4
+ class Node
5
+ extend Forwardable
6
+ include Enumerable
7
+
8
+ def_delegators :node,
9
+ :array?,
10
+ :each,
11
+ :each_key,
12
+ :each_pair,
13
+ :hash?,
14
+ :keys,
15
+ :key?,
16
+ :has_key?,
17
+ :to_a,
18
+ :to_hash,
19
+ :to_s,
20
+ :value?,
21
+ :values,
22
+ :values_at
23
+
24
+ def initialize(collection)
25
+ data = data_of(collection)
26
+ @node = ::ConfigPlus::Collection.generate_for(data)
27
+ self.merge!(data) if hash
6
28
  end
7
29
 
8
30
  def [](key)
9
- value = self.fetch(key.to_s, nil)
10
- value = self.fetch(key.to_i, nil) if
11
- value.nil? and key.to_s =~ /\A\d+\z/
12
- return value unless value.is_a?(Hash)
31
+ value = node[key]
13
32
  return value if value.is_a?(self.class)
14
33
 
15
- self.store(key.to_s, self.class.new(value))
34
+ case value
35
+ when Hash, Array, ::ConfigPlus::Collection
36
+ node.store(key.to_s, self.class.new(value))
37
+ else
38
+ value
39
+ end
16
40
  end
17
41
 
18
42
  def get(path)
@@ -22,29 +46,57 @@ module ConfigPlus
22
46
  self[key].get(rest)
23
47
  end
24
48
 
25
- def merge!(hash)
26
- result = super
27
- hash.keys.each {|k| define_accessor(k) }
28
- result
49
+ def dig(*keys)
50
+ key = keys.first
51
+ rest = keys[1..-1]
52
+ return self[key] if rest.empty?
53
+ return nil unless self[key]
54
+ self[key].dig(*rest)
55
+ end
56
+
57
+ def merge(collection)
58
+ data = data_of(collection)
59
+ self.class.new(node.merge(convert(data)))
60
+ end
61
+
62
+ def ==(object)
63
+ node.data == data_of(object)
29
64
  end
30
65
 
31
- def merge(hash)
32
- result = super
33
- result.instance_eval {
34
- hash.keys.each {|k| define_accessor(k) }
66
+ protected
67
+
68
+ attr_reader :node
69
+
70
+ def merge!(collection)
71
+ data = data_of(collection)
72
+ node.merge!(convert(data)).tap {
73
+ (node.hash? ? data : node).keys.each {|k| define_accessor(k) }
35
74
  }
36
- result
37
75
  end
38
76
 
39
77
  private
40
78
 
79
+ def data_of(collection)
80
+ collection.is_a?(self.class) ? collection.node : collection
81
+ end
82
+
83
+ def convert(collection)
84
+ case collection
85
+ when Array
86
+ collection.map do |data|
87
+ data.is_a?(Array) || data.is_a?(Hash) ? self.class.new(data) : data
88
+ end
89
+ else
90
+ collection
91
+ end
92
+ end
93
+
41
94
  def define_accessor(method_name)
42
- return unless method_name.is_a?(String) or
43
- method_name.is_a?(Symbol)
44
- return if respond_to?(method_name) or
45
- private_methods.include?(method_name.to_sym)
46
- singleton_class.class_eval do
47
- define_method method_name, lambda { self[method_name] }
95
+ name = method_name.to_s
96
+ return if respond_to?(name) or
97
+ private_methods.include?(name.to_sym)
98
+ singleton_class.class_exec(self) do |node|
99
+ define_method name, lambda { node[method_name] }
48
100
  end
49
101
  end
50
102
  end
@@ -0,0 +1,10 @@
1
+ module ConfigPlus
2
+ module Single
3
+ private
4
+
5
+ def generate_config(source, options={})
6
+ opt = options.merge(to: self) unless options.key?(:to) or options.key('to')
7
+ ::ConfigPlus.single_generate(source, opt || options)
8
+ end
9
+ end
10
+ end
@@ -1,3 +1,3 @@
1
1
  module ConfigPlus
2
- VERSION = '0.0.5'
2
+ VERSION = '0.0.7'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: config_plus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - m4oda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-07 00:00:00.000000000 Z
11
+ date: 2018-02-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -35,6 +35,7 @@ files:
35
35
  - README.md
36
36
  - lib/config_plus.rb
37
37
  - lib/config_plus/base.rb
38
+ - lib/config_plus/collection.rb
38
39
  - lib/config_plus/config.rb
39
40
  - lib/config_plus/default_loader_logic.rb
40
41
  - lib/config_plus/erb_yaml_loader_logic.rb
@@ -42,6 +43,7 @@ files:
42
43
  - lib/config_plus/loader.rb
43
44
  - lib/config_plus/merger.rb
44
45
  - lib/config_plus/node.rb
46
+ - lib/config_plus/single.rb
45
47
  - lib/config_plus/version.rb
46
48
  homepage: https://github.com/m4oda/config_plus
47
49
  licenses:
@@ -63,7 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
65
  version: '0'
64
66
  requirements: []
65
67
  rubyforge_project:
66
- rubygems_version: 2.5.1
68
+ rubygems_version: 2.6.8
67
69
  signing_key:
68
70
  specification_version: 4
69
71
  summary: An easy-to-use, powerful configuration module using YAML files