confo-config 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e18009a32d37da15b10c87cff286b37be9ff6a2e
4
+ data.tar.gz: 0e2ad064b148ef7237ec98722afebb703dd8b2bb
5
+ SHA512:
6
+ metadata.gz: f759fb4b9277b5f78c559cda2e270d97d2741827f2536e3cb40578d97f902eda3eaceac0906bcef6cc0b898fda0fdf1f0f105712d5fcd1570342d67eb453c548
7
+ data.tar.gz: d05dbef7d09242b374b5872202349dd315c7899302554e08dd143db3c30b55a5f26f7446d50e588df09bf43aebb69be38425ac63648a44debfec0f8e7cc475ae
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ .idea
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in confo.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Yaroslav Konoplov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # ConfoConfig
2
+
3
+ ## A little configuration DSL
4
+ ```ruby
5
+ configuration do
6
+ autocomplete_limit 20
7
+ autocomplete_phrase_length 2
8
+
9
+ i18n do
10
+ available_locales [:en, :ru]
11
+ default_locale :en
12
+ end
13
+
14
+ list do
15
+ single_actions { can :update, :toggle, :delete, :preview }
16
+ plural_actions { can :create, :filter, :export, :search }
17
+
18
+ highlight { role admin: :red, user: :gray }
19
+
20
+ configure(:column, :avatar) { type :photo }
21
+
22
+ columns { include :name, :avatar, :role }
23
+ end
24
+
25
+ form do
26
+ configure(:input, :avatar) { type :photo }
27
+ actions { can :save, :cancel }
28
+ end
29
+ end
30
+ ```
31
+
32
+ ## Gemfile
33
+ ```ruby
34
+ gem 'confo-config', github: 'yivo/confo-config'
35
+ ```
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/confo.gemspec ADDED
@@ -0,0 +1,19 @@
1
+ require File.expand_path('../lib/confo/version', __FILE__)
2
+
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'
12
+
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']
17
+
18
+ spec.add_dependency 'activesupport', '~> 4.0' # 4.0 <= version < 5.0
19
+ end
@@ -0,0 +1,80 @@
1
+ module Confo
2
+ class Collection
3
+ include Enumerable
4
+
5
+ attr_reader :behaviour_options
6
+
7
+ def initialize(behaviour_options = {}, &block)
8
+ @behaviour_options = behaviour_options
9
+ configure(&block) if block
10
+ end
11
+
12
+ def define(id, options = nil, construct_options = nil, &block)
13
+ id = convert_id(id)
14
+ config = storage[id]
15
+ config ||= begin
16
+ config_class = Confo.call(self, :config_class, id, construct_options)
17
+ config = Confo.call(self, :construct_config, config_class, id, construct_options)
18
+ storage[id] = config
19
+ config.set(:name, id)
20
+ config
21
+ end
22
+
23
+ config.set(options) if options
24
+ config.configure(&block) if block
25
+ config
26
+ end
27
+
28
+ def get(id)
29
+ define(id)
30
+ end
31
+
32
+ def set(id, config)
33
+ storage[convert_id(id)] = config
34
+ end
35
+
36
+ alias [] get
37
+ alias []= set
38
+
39
+ def configure(*args, &block)
40
+ args.present? ? define(*args).configure(&block) : instance_eval(&block)
41
+ end
42
+
43
+ def exists?(id)
44
+ storage[convert_id(id)].present?
45
+ end
46
+
47
+ def each(&block)
48
+ storage.each { |k, v| block.call(v) }
49
+ end
50
+
51
+ def to_a
52
+ storage.values
53
+ end
54
+
55
+ def to_hash
56
+ storage.reduce({}) do |memo, (id, instance)|
57
+ memo[id] = Confo.convert_to_hash(instance)
58
+ memo
59
+ end
60
+ end
61
+
62
+ protected
63
+
64
+ def config_class(config_id, config_options)
65
+ config_options.try(:[], :class_name).try(:safe_constantize) || Config
66
+ end
67
+
68
+ def construct_config(config_class)
69
+ config_class.new
70
+ end
71
+
72
+ def storage
73
+ @storage ||= ActiveSupport::OrderedHash.new
74
+ end
75
+
76
+ def convert_id(id)
77
+ id.to_sym
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,184 @@
1
+ module Confo
2
+ module OptionsManager
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ # Define option accessors.
8
+ def option_accessor(*names)
9
+ names.each do |name|
10
+ define_option_functional_accessor(name)
11
+ define_option_writer(name)
12
+ end
13
+ end
14
+
15
+ def define_option_functional_accessor(name)
16
+ define_method("#{name}") do |*args|
17
+ if args.size > 0
18
+ raw_set(name, args.first)
19
+ self
20
+ else
21
+ raw_get(name)
22
+ end
23
+ end
24
+ end
25
+
26
+ def define_option_writer(name)
27
+ define_method("#{name}=") do |value|
28
+ raw_set(name, value)
29
+ self
30
+ end
31
+ end
32
+ end
33
+
34
+ # Returns option value:
35
+ # obj.get(:option) => 'value'
36
+ # obj.get('option') => 'value'
37
+ #
38
+ # obj.set :option, -> { 'value' }
39
+ # obj.get(:option) => 'value'
40
+ #
41
+ # obj.set :option, -> (arg) { 'value' }
42
+ # obj.get(:option) => -> (arg) { 'value' }
43
+ def get(option)
44
+ public_get(option)
45
+ end
46
+
47
+ # Alias for +get+.
48
+ alias [] get
49
+
50
+ protected
51
+
52
+ # Method to get an option.
53
+ # If there is an option accessor defined then it will be used.
54
+ # In other cases +raw_get+ will be used.
55
+ def public_get(option)
56
+ respond_to?(option) ? send(option) : raw_get(option)
57
+ end
58
+
59
+ # Internal method to get an option.
60
+ # If value is callable without arguments
61
+ # it will be called and result will be returned.
62
+ def raw_get(option)
63
+ value = storage[option]
64
+ Confo.callable_without_arguments?(value) ? value.call : value
65
+ end
66
+
67
+ public
68
+
69
+ # Sets option:
70
+ # obj.set(:option, 'value')
71
+ # obj.set('option', 'value')
72
+ # obj.set({ foo: '1', bar: '2', baz: -> { 3 } })
73
+ def set(arg, *args)
74
+ if arg.kind_of?(Hash)
75
+ arg.each { |k, v| public_set(k, v) }
76
+ elsif args.size > 0
77
+ public_set(arg, args.first)
78
+ end
79
+ self
80
+ end
81
+
82
+ # Alias for +set+.
83
+ alias []= set
84
+
85
+ protected
86
+
87
+ # Method to set an option.
88
+ # If there is an option accessor defined then it will be used.
89
+ # In other cases +raw_set+ will be used.
90
+ def public_set(option, value)
91
+ method = "#{option}="
92
+ respond_to?(method) ? send(method, value) : raw_set(option, value)
93
+ end
94
+
95
+ # Internal method to set option.
96
+ def raw_set(option, value)
97
+ storage[option] = value
98
+ end
99
+
100
+ public
101
+
102
+ # Sets option only if it is not set yet:
103
+ # obj.set_at_first(:option, 1)
104
+ # obj.get(:option) => 1
105
+ # obj.set_at_first(:option, 2)
106
+ # obj.get(:option) => 1
107
+ def set_at_first(*args)
108
+ set?(*args)
109
+ self
110
+ end
111
+
112
+ # Alias for +set_at_first+.
113
+ alias init set_at_first
114
+
115
+ # Option accessor in functional style:
116
+ # obj.option(:option, 'value')
117
+ # obj.option(:option) => 'value'
118
+ def option(option, *args)
119
+ args.size > 0 ? set(option, args.first) : get(option)
120
+ end
121
+
122
+ # Checks if option is set.
123
+ # Works similar to set if value passed but sets only uninitialized options.
124
+ def set?(arg, *rest_args)
125
+ if arg.kind_of?(Hash)
126
+ arg.each { |k, v| set(k, v) unless set?(k) }
127
+ nil
128
+ elsif rest_args.size > 0
129
+ set(arg, rest_args.first) unless set?(arg)
130
+ true
131
+ else
132
+ storage.has_key?(arg)
133
+ end
134
+ end
135
+
136
+ # If you expect computed value you can pass arguments to it:
137
+ # obj.set :calculator, -> (num) { num * 2 }
138
+ # obj.result_of :calculator, 2 => 4
139
+ def result_of(option, *args)
140
+ Confo.result_of(get(option), *args)
141
+ end
142
+
143
+ # Unsets option.
144
+ def unset(option)
145
+ storage.delete(option)
146
+ self
147
+ end
148
+
149
+ # Returns option names as array of symbols.
150
+ def keys
151
+ storage.reduce([]) do |memo, k, v|
152
+ memo << k.to_sym
153
+ memo
154
+ end
155
+ end
156
+
157
+ # Returns option values as array.
158
+ def values
159
+ storage.values
160
+ end
161
+
162
+ # Returns all options at once.
163
+ # obj.options => { option: 'value' }
164
+ def options
165
+ options = storage.dup
166
+ options.each { |k, v| options[k] = get(k) }
167
+ options
168
+ end
169
+
170
+ protected
171
+
172
+ def storage
173
+ @storage ||= OptionsStorage.new
174
+ end
175
+ end
176
+
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
183
+ end
184
+ end
@@ -0,0 +1,101 @@
1
+ module Confo
2
+ module SubconfigsManager
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def includes_config(arg, options = {})
7
+ @subconfigs_options ||= {}
8
+
9
+ # Support different syntaxes:
10
+ # includes_config :actions
11
+ # includes_config of: :actions
12
+ # includes_config for: :actions
13
+ name = (arg.kind_of?(Hash) ? arg[:of] || arg[:for] : arg).to_sym
14
+ new_options = @subconfigs_options[name]
15
+ new_options ||= { name: name, fallback_class_name: 'Confo::Config' }
16
+ new_options.merge!(options)
17
+
18
+ @subconfigs_options[name] = new_options
19
+
20
+ define_subconfig_reader(name, new_options)
21
+ self
22
+ end
23
+
24
+ def subconfigs_options
25
+ all_options = @subconfigs_options ? @subconfigs_options.dup : {}
26
+ if superclass.respond_to?(:subconfigs_options)
27
+ superclass.subconfigs_options.each do |name, options|
28
+ new_options = {}
29
+ new_options.merge!(options[name]) if options[name]
30
+ new_options.merge!(options)
31
+ options[name] = new_options
32
+ end
33
+ end
34
+ all_options
35
+ end
36
+
37
+ def define_subconfig_reader(subconfig_name, subconfig_options)
38
+ define_method(subconfig_name) do |options = nil, overrides = nil, &block|
39
+ subconfig_internal(subconfig_name, options, overrides, &block)
40
+ end
41
+ end
42
+ end
43
+
44
+ def subconfigs
45
+ unless @all_subconfigs_loaded
46
+ self.class.subconfigs_options.each { |name, options| subconfig(name) }
47
+ @all_subconfigs_loaded = true
48
+ end
49
+ subconfig_instances
50
+ end
51
+
52
+ def subconfig(subconfig_name, options = nil, overrides = nil, &block)
53
+ respond_to?(subconfig_name) ?
54
+ send(subconfig_name, options, overrides, &block) :
55
+ subconfig_internal(subconfig_name, options, overrides, &block)
56
+ end
57
+
58
+ def subconfig_exists?(subconfig_name)
59
+ subconfig_instances.exists?(subconfig_name)
60
+ end
61
+
62
+ protected
63
+
64
+ def subconfig_instances
65
+ @subconfig_instances ||= Collection.new
66
+ end
67
+
68
+ def subconfig_internal(subconfig_name, options = nil, overrides = nil, &block)
69
+ unless subconfig_exists?(subconfig_name)
70
+ subconfig_options = self.class.subconfigs_options[subconfig_name].try(:dup) || {}
71
+ subconfig_options.merge!(overrides) if overrides
72
+
73
+ subconfig_class = Confo.call(self, :subconfig_class, subconfig_name, subconfig_options)
74
+ subconfig_instance = Confo.call(self, :construct_subconfig, subconfig_class, subconfig_options)
75
+
76
+ subconfig_instance.set(:name, subconfig_name) unless subconfig_instance.kind_of?(Collection)
77
+ subconfig_instances.set(subconfig_name, subconfig_instance)
78
+ end
79
+ subconfig_instance = subconfig_instances.get(subconfig_name)
80
+ subconfig_instance.set(options) if options
81
+ subconfig_instance.configure(&block) if block
82
+ subconfig_instance
83
+ end
84
+
85
+ def construct_subconfig(subconfig_class)
86
+ subconfig_class.new
87
+ end
88
+
89
+ def subconfig_class(subconfig_name, subconfig_options)
90
+ if class_name = subconfig_options[:class_name]
91
+ class_name.to_s.camelize
92
+ else
93
+ guess_subconfig_class_name(subconfig_name)
94
+ end.safe_constantize || subconfig_options.fetch(:fallback_class_name, 'Confo::Config').constantize
95
+ end
96
+
97
+ def guess_subconfig_class_name(subconfig_name)
98
+ "#{subconfig_name.to_s.camelize}Config"
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,121 @@
1
+ require_relative '../confo.rb'
2
+
3
+ module Confo
4
+ class Config
5
+ include OptionsManager
6
+ include SubconfigsManager
7
+
8
+ attr_reader :behaviour_options
9
+
10
+ def initialize(behaviour_options = {}, &block)
11
+ @behaviour_options = behaviour_options
12
+ preconfigure
13
+ configure(&block) if block
14
+ end
15
+
16
+ def configure(*args, &block)
17
+ case args.size
18
+
19
+ # Current config configuration:
20
+ # object.configure { }
21
+ when 0
22
+ instance_eval(&block) if block
23
+ self
24
+
25
+ when 1, 2, 3
26
+ arg1, arg2, arg3 = args
27
+ arg1_hash = arg1.kind_of?(Hash)
28
+
29
+ # Hash-based collection syntax:
30
+ # object.configure(property: :id) { }
31
+ # object.configure(property: :id, {option: :value}) { }
32
+ #
33
+ # Full definition syntax:
34
+ # object.configure(:property, :id) { }
35
+ # object.configure(:property, :id, {option: :value}) { }
36
+ if arg1_hash || (args.size == 2 && arg2.kind_of?(Hash) == false)
37
+ subconfig_name = (arg1_hash ? arg1.keys.first : arg1).to_s.pluralize
38
+ config_id = arg1_hash ? arg1.values.first : arg2
39
+ options = arg1_hash ? arg2 : arg3
40
+ subconfig(subconfig_name, options, fallback_class_name: 'Confo::Collection')
41
+ .configure(config_id, &block)
42
+ else
43
+
44
+ # Subconfig configuration:
45
+ # object.configure(:description)
46
+ # object.configure(:description, {option: :value})
47
+ subconfig(arg1, arg2, &block)
48
+ end
49
+
50
+ else self
51
+ end
52
+ end
53
+
54
+ def method_missing(name, *args, &block)
55
+ case args.size
56
+ when 0
57
+ if block
58
+ # Wants to configure subconfig:
59
+ # object.description { }
60
+ subconfig(name, &block)
61
+ else
62
+
63
+ # Wants one of the following:
64
+ # - access subconfig
65
+ # - access option
66
+ subconfig_exists?(name) ? subconfig(name) : option(normalize_option(name))
67
+ end
68
+
69
+ when 1
70
+ arg = args.first
71
+
72
+ # Wants to access collection:
73
+ # object.properties :id { }
74
+ if (arg.is_a?(String) || arg.is_a?(Symbol)) && subconfig_exists?(name)
75
+ subconfig(name.to_s.pluralize, arg, &block)
76
+ else
77
+
78
+ # Wants to access option:
79
+ # object.cache = :none
80
+ # object.cache :none
81
+ option(normalize_option(name), arg)
82
+ end
83
+
84
+ else
85
+ option(normalize_option(name), *args)
86
+ end
87
+ end
88
+
89
+ def to_hash
90
+ {}.merge!(options.to_hash).merge!(subconfigs.to_hash)
91
+ end
92
+
93
+ protected
94
+
95
+ def preconfigure
96
+ preconfigurator_class = lookup_preconfigurator_class
97
+ if preconfigurator_class
98
+ preconfigurator_class.instance.preconfigure(self)
99
+ true
100
+ else
101
+ false
102
+ end
103
+ end
104
+
105
+ def lookup_preconfigurator_class
106
+ guess_preconfigurator_class_name.safe_constantize
107
+ end
108
+
109
+ def configurable_component_name
110
+ self.class.name.demodulize.sub(/Config\Z/, '')
111
+ end
112
+
113
+ def guess_preconfigurator_class_name
114
+ "#{configurable_component_name}Preconfigurator"
115
+ end
116
+
117
+ def normalize_option(name)
118
+ name.to_s.sub(/=+\Z/, '').to_sym
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,12 @@
1
+ module Confo
2
+ class Preconfigurator
3
+ include Singleton
4
+
5
+ def preconfigure(config)
6
+ raise PreconfiguratorNotImplementedError
7
+ end
8
+ end
9
+
10
+ class PreconfiguratorNotImplementedError < ::StandardError
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module Confo
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1 @@
1
+ require_relative 'confo.rb'
data/lib/confo.rb ADDED
@@ -0,0 +1,43 @@
1
+ require 'active_support/all'
2
+ require 'confo/version'
3
+ require 'confo/concerns/options_manager'
4
+ require 'confo/concerns/subconfigs_manager'
5
+ require 'confo/config'
6
+ require 'confo/collection'
7
+ require 'confo/preconfigurator'
8
+
9
+ module Confo
10
+ class << self
11
+ def result_of(value, *args)
12
+ if value.respond_to?(:call)
13
+ _args_ = value.arity < 0 ? args : args[0...value.arity]
14
+ value.call(*args)
15
+ else
16
+ value
17
+ end
18
+ end
19
+
20
+ def callable_without_arguments?(obj)
21
+ obj.respond_to?(:call) && (!obj.respond_to?(:arity) || obj.arity == 0)
22
+ end
23
+
24
+ def convert_to_hash(value)
25
+ if value.is_a?(Hash)
26
+ value.to_hash
27
+ elsif value.is_a?(Array)
28
+ value.map { |e| convert_to_hash(e) }
29
+ else
30
+ value.respond_to?(:to_hash) ? value.to_hash : value
31
+ end
32
+ end
33
+
34
+ def call_method_with_floating_arguments(object, method, *args)
35
+ callable = object.method(method)
36
+ arity = callable.arity
37
+ resized_args = arity < 0 ? args : args[0...arity]
38
+ callable.call(*resized_args)
39
+ end
40
+
41
+ alias call call_method_with_floating_arguments
42
+ end
43
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: confo-config
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Yaroslav Konoplov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ description: Little configuration framework
28
+ email:
29
+ - yaroslav@inbox.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - Gemfile
36
+ - LICENSE.txt
37
+ - README.md
38
+ - Rakefile
39
+ - confo.gemspec
40
+ - lib/confo-config.rb
41
+ - lib/confo.rb
42
+ - lib/confo/collection.rb
43
+ - lib/confo/concerns/options_manager.rb
44
+ - lib/confo/concerns/subconfigs_manager.rb
45
+ - lib/confo/config.rb
46
+ - lib/confo/preconfigurator.rb
47
+ - lib/confo/version.rb
48
+ homepage: http://github.com/yivo/confo-config
49
+ licenses:
50
+ - MIT
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.4.8
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Little configuration framework
72
+ test_files: []