config_plus 0.0.5 → 0.0.7

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: 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