confo-config 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: []