super-smart-sys 0.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.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/config-5.6.1/CHANGELOG.md +332 -0
  3. data/config-5.6.1/CONTRIBUTING.md +38 -0
  4. data/config-5.6.1/LICENSE.md +26 -0
  5. data/config-5.6.1/README.md +615 -0
  6. data/config-5.6.1/config.gemspec +62 -0
  7. data/config-5.6.1/lib/config/configuration.rb +36 -0
  8. data/config-5.6.1/lib/config/dry_validation_requirements.rb +25 -0
  9. data/config-5.6.1/lib/config/error.rb +4 -0
  10. data/config-5.6.1/lib/config/integrations/heroku.rb +59 -0
  11. data/config-5.6.1/lib/config/integrations/rails/railtie.rb +38 -0
  12. data/config-5.6.1/lib/config/integrations/sinatra.rb +26 -0
  13. data/config-5.6.1/lib/config/options.rb +195 -0
  14. data/config-5.6.1/lib/config/rack/reloader.rb +15 -0
  15. data/config-5.6.1/lib/config/sources/env_source.rb +94 -0
  16. data/config-5.6.1/lib/config/sources/hash_source.rb +16 -0
  17. data/config-5.6.1/lib/config/sources/yaml_source.rb +32 -0
  18. data/config-5.6.1/lib/config/tasks/heroku.rake +7 -0
  19. data/config-5.6.1/lib/config/validation/error.rb +15 -0
  20. data/config-5.6.1/lib/config/validation/schema.rb +23 -0
  21. data/config-5.6.1/lib/config/validation/validate.rb +29 -0
  22. data/config-5.6.1/lib/config/version.rb +3 -0
  23. data/config-5.6.1/lib/config.rb +93 -0
  24. data/config-5.6.1/lib/generators/config/install_generator.rb +32 -0
  25. data/config-5.6.1/lib/generators/config/templates/config.rb +77 -0
  26. data/config-5.6.1/lib/generators/config/templates/settings/development.yml +0 -0
  27. data/config-5.6.1/lib/generators/config/templates/settings/production.yml +0 -0
  28. data/config-5.6.1/lib/generators/config/templates/settings/test.yml +0 -0
  29. data/config-5.6.1/lib/generators/config/templates/settings.local.yml +0 -0
  30. data/config-5.6.1/lib/generators/config/templates/settings.yml +0 -0
  31. data/super-smart-sys.gemspec +11 -0
  32. metadata +70 -0
@@ -0,0 +1,36 @@
1
+ module Config
2
+ # The main configuration backbone
3
+ class Configuration < Module
4
+ # Accepts configuration options,
5
+ # initializing a module that can be used to extend
6
+ # the necessary class with the provided config methods
7
+ def initialize(**attributes)
8
+ attributes.each do |name, default|
9
+ define_reader(name, default)
10
+ define_writer(name)
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def define_reader(name, default)
17
+ variable = :"@#{name}"
18
+
19
+ define_method(name) do
20
+ if instance_variable_defined?(variable)
21
+ instance_variable_get(variable)
22
+ else
23
+ default
24
+ end
25
+ end
26
+ end
27
+
28
+ def define_writer(name)
29
+ variable = :"@#{name}"
30
+
31
+ define_method("#{name}=") do |value|
32
+ instance_variable_set(variable, value)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Config
4
+ module DryValidationRequirements
5
+ VERSIONS = ['~> 1.0', '>= 1.0.0'].freeze
6
+
7
+ def self.load_dry_validation!
8
+ return if defined?(@load_dry_validation)
9
+
10
+ begin
11
+ require 'dry/validation/version'
12
+ version = Gem::Version.new(Dry::Validation::VERSION)
13
+ unless VERSIONS.all? { |req| Gem::Requirement.new(req).satisfied_by?(version) }
14
+ raise LoadError
15
+ end
16
+ rescue LoadError
17
+ raise ::Config::Error, "Could not find a dry-validation version matching requirements (#{VERSIONS.map(&:inspect) * ','})"
18
+ end
19
+
20
+ require 'dry/validation'
21
+ @load_dry_validation = true
22
+ nil
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,4 @@
1
+ module Config
2
+ class Error < StandardError
3
+ end
4
+ end
@@ -0,0 +1,59 @@
1
+ require 'bundler'
2
+
3
+ module Config
4
+ module Integrations
5
+ class Heroku < Struct.new(:app)
6
+ def invoke
7
+ puts 'Setting vars...'
8
+ heroku_command = "config:set #{vars}"
9
+ heroku(heroku_command)
10
+ puts 'Vars set:'
11
+ puts heroku_command
12
+ end
13
+
14
+ def vars
15
+ # Load only local options to Heroku
16
+ Config.load_and_set_settings(
17
+ Rails.root.join("config", "#{Config.file_name}.local.yml").to_s,
18
+ Rails.root.join("config", Config.dir_name, "#{environment}.local.yml").to_s,
19
+ Rails.root.join("config", "environments", "#{environment}.local.yml").to_s
20
+ )
21
+
22
+ out = ''
23
+ dotted_hash = to_dotted_hash Kernel.const_get(Config.const_name).to_hash, {}, Config.const_name
24
+ dotted_hash.each {|key, value| out += " #{key}=#{value} "}
25
+ out
26
+ end
27
+
28
+ def environment
29
+ heroku("run 'echo $RAILS_ENV'").chomp[/(\w+)\z/]
30
+ end
31
+
32
+ def heroku(command)
33
+ with_app = app ? " --app #{app}" : ""
34
+ `heroku #{command}#{with_app}`
35
+ end
36
+
37
+ def `(command)
38
+ Bundler.with_clean_env { super }
39
+ end
40
+
41
+ def to_dotted_hash(source, target = {}, namespace = nil)
42
+ prefix = "#{namespace}." if namespace
43
+ case source
44
+ when Hash
45
+ source.each do |key, value|
46
+ to_dotted_hash(value, target, "#{prefix}#{key}")
47
+ end
48
+ when Array
49
+ source.each_with_index do |value, index|
50
+ to_dotted_hash(value, target, "#{prefix}#{index}")
51
+ end
52
+ else
53
+ target[namespace] = source
54
+ end
55
+ target
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,38 @@
1
+ module Config
2
+ module Integrations
3
+ module Rails
4
+ class Railtie < ::Rails::Railtie
5
+ def preload
6
+ # Manually load the custom initializer before everything else
7
+ initializer = ::Rails.root.join('config', 'initializers', 'config.rb')
8
+ require initializer if File.exist?(initializer)
9
+
10
+ # Parse the settings before any of the initializers
11
+ Config.load_and_set_settings(
12
+ Config.setting_files(::Rails.root.join('config'), Config.environment.nil? ? ::Rails.env : Config.environment.to_sym)
13
+ )
14
+ end
15
+
16
+ # Load rake tasks (eg. Heroku)
17
+ rake_tasks do
18
+ Dir[File.join(File.dirname(__FILE__), '../tasks/*.rake')].each { |f| load f }
19
+ end
20
+
21
+ config.before_configuration { preload }
22
+
23
+ # Development environment should reload settings on every request
24
+ if ::Rails.env.development?
25
+ initializer :config_reload_on_development do
26
+ ActiveSupport.on_load :action_controller_base do
27
+ if ::Rails::VERSION::MAJOR >= 4
28
+ prepend_before_action { ::Config.reload! }
29
+ else
30
+ prepend_before_filter { ::Config.reload! }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,26 @@
1
+ require "config/rack/reloader"
2
+
3
+ module Config
4
+ # provide helper to register within your Sinatra app
5
+ #
6
+ # set :root, File.dirname(__FILE__)
7
+ # register Config
8
+ #
9
+ def self.registered(app)
10
+ app.configure do |inner_app|
11
+
12
+ env = inner_app.environment || ENV["RACK_ENV"]
13
+ root = inner_app.root
14
+
15
+ # use Padrino settings if applicable
16
+ if defined?(Padrino)
17
+ env = Padrino.env if Padrino.respond_to?(:env)
18
+ root = Padrino.root if Padrino.respond_to?(:root)
19
+ end
20
+
21
+ Config.load_and_set_settings(Config.setting_files(File.join(root, 'config'), env))
22
+
23
+ inner_app.use(::Config::Rack::Reloader) if inner_app.development?
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,195 @@
1
+ require 'ostruct'
2
+ require 'config/validation/validate'
3
+
4
+ module Config
5
+ class Options < OpenStruct
6
+ include Enumerable
7
+ include Validation::Validate
8
+
9
+ def keys
10
+ marshal_dump.keys
11
+ end
12
+
13
+ def empty?
14
+ marshal_dump.empty?
15
+ end
16
+
17
+ def add_source!(source)
18
+ # handle yaml file paths
19
+ source = (Sources::YAMLSource.new(source)) if source.is_a?(String) || source.is_a?(Pathname)
20
+ source = (Sources::HashSource.new(source)) if source.is_a?(Hash)
21
+
22
+ @config_sources ||= []
23
+ @config_sources << source
24
+ end
25
+
26
+ def prepend_source!(source)
27
+ source = (Sources::YAMLSource.new(source)) if source.is_a?(String) || source.is_a?(Pathname)
28
+ source = (Sources::HashSource.new(source)) if source.is_a?(Hash)
29
+
30
+ @config_sources ||= []
31
+ @config_sources.unshift(source)
32
+ end
33
+
34
+ # look through all our sources and rebuild the configuration
35
+ def reload!
36
+ conf = {}
37
+ @config_sources.each do |source|
38
+ source_conf = source.load
39
+
40
+ if conf.empty?
41
+ conf = source_conf
42
+ else
43
+ DeepMerge.deep_merge!(
44
+ source_conf,
45
+ conf,
46
+ preserve_unmergeables: false,
47
+ knockout_prefix: Config.knockout_prefix,
48
+ overwrite_arrays: Config.overwrite_arrays,
49
+ merge_nil_values: Config.merge_nil_values,
50
+ merge_hash_arrays: Config.merge_hash_arrays
51
+ )
52
+ end
53
+ end
54
+
55
+ # swap out the contents of the OStruct with a hash (need to recursively convert)
56
+ marshal_load(__convert(conf).marshal_dump)
57
+
58
+ validate!
59
+
60
+ self
61
+ end
62
+
63
+ alias :load! :reload!
64
+
65
+ def reload_from_files(*files)
66
+ Config.load_and_set_settings(files)
67
+ reload!
68
+ end
69
+
70
+ def to_hash
71
+ result = {}
72
+ marshal_dump.each do |k, v|
73
+ if v.instance_of? Config::Options
74
+ result[k] = v.to_hash
75
+ elsif v.instance_of? Array
76
+ result[k] = descend_array(v)
77
+ else
78
+ result[k] = v
79
+ end
80
+ end
81
+ result
82
+ end
83
+
84
+ alias :to_h :to_hash
85
+
86
+ def each(*args, &block)
87
+ marshal_dump.each(*args, &block)
88
+ end
89
+
90
+ def to_json(*args)
91
+ require "json" unless defined?(JSON)
92
+ to_hash.to_json(*args)
93
+ end
94
+
95
+ def as_json(options = nil)
96
+ to_hash.as_json(options)
97
+ end
98
+
99
+ def merge!(hash)
100
+ current = to_hash
101
+ DeepMerge.deep_merge!(
102
+ hash.dup,
103
+ current,
104
+ preserve_unmergeables: false,
105
+ knockout_prefix: Config.knockout_prefix,
106
+ overwrite_arrays: Config.overwrite_arrays,
107
+ merge_nil_values: Config.merge_nil_values,
108
+ merge_hash_arrays: Config.merge_hash_arrays
109
+ )
110
+ marshal_load(__convert(current).marshal_dump)
111
+ self
112
+ end
113
+
114
+ # Some keywords that don't play nicely with OpenStruct
115
+ SETTINGS_RESERVED_NAMES = %w[select collect test count zip min max exit! table].freeze
116
+
117
+ # Some keywords that don't play nicely with Rails 7.*
118
+ RAILS_RESERVED_NAMES = %w[maximum minimum].freeze
119
+
120
+ # An alternative mechanism for property access.
121
+ # This let's you do foo['bar'] along with foo.bar.
122
+ def [](param)
123
+ return super if SETTINGS_RESERVED_NAMES.include?(param)
124
+ return super if RAILS_RESERVED_NAMES.include?(param)
125
+ public_send("#{param}")
126
+ end
127
+
128
+ def []=(param, value)
129
+ send("#{param}=", value)
130
+ end
131
+
132
+ SETTINGS_RESERVED_NAMES.each do |name|
133
+ define_method name do
134
+ self[name]
135
+ end
136
+ end
137
+
138
+ RAILS_RESERVED_NAMES.each do |name|
139
+ define_method name do
140
+ self[name]
141
+ end
142
+ end
143
+
144
+ def key?(key)
145
+ @table.key?(key)
146
+ end
147
+
148
+ def has_key?(key)
149
+ @table.has_key?(key)
150
+ end
151
+
152
+ def method_missing(method_name, *args)
153
+ if Config.fail_on_missing && method_name !~ /.*(?==\z)/m
154
+ raise KeyError, "key not found: #{method_name.inspect}" unless key?(method_name)
155
+ end
156
+ super
157
+ end
158
+
159
+ def respond_to_missing?(*args)
160
+ super
161
+ end
162
+
163
+ protected
164
+
165
+ def descend_array(array)
166
+ array.map do |value|
167
+ if value.instance_of? Config::Options
168
+ value.to_hash
169
+ elsif value.instance_of? Array
170
+ descend_array(value)
171
+ else
172
+ value
173
+ end
174
+ end
175
+ end
176
+
177
+ # Recursively converts Hashes to Options (including Hashes inside Arrays)
178
+ def __convert(h) #:nodoc:
179
+ s = self.class.new
180
+
181
+ h.each do |k, v|
182
+ k = k.to_s if !k.respond_to?(:to_sym) && k.respond_to?(:to_s)
183
+
184
+ if v.is_a?(Hash)
185
+ v = v["type"] == "hash" ? v["contents"] : __convert(v)
186
+ elsif v.is_a?(Array)
187
+ v = v.collect { |e| e.instance_of?(Hash) ? __convert(e) : e }
188
+ end
189
+
190
+ s[k] = v
191
+ end
192
+ s
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,15 @@
1
+ module Config
2
+ module Rack
3
+ # Rack middleware the reloads Config on every request (only use in dev mode)
4
+ class Reloader
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ Config.reload!
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,94 @@
1
+ module Config
2
+ module Sources
3
+ # Allows settings to be loaded from a "flat" hash with string keys, like ENV.
4
+ class EnvSource
5
+ attr_reader :prefix
6
+ attr_reader :separator
7
+ attr_reader :converter
8
+ attr_reader :parse_values
9
+ attr_reader :parse_arrays
10
+
11
+ def initialize(env,
12
+ prefix: Config.env_prefix || Config.const_name,
13
+ separator: Config.env_separator,
14
+ converter: Config.env_converter,
15
+ parse_values: Config.env_parse_values,
16
+ parse_arrays: Config.env_parse_arrays)
17
+ @env = env
18
+ @prefix = prefix.to_s.split(separator)
19
+ @separator = separator
20
+ @converter = converter
21
+ @parse_values = parse_values
22
+ @parse_arrays = parse_arrays
23
+ end
24
+
25
+ def load
26
+ return {} if @env.nil? || @env.empty?
27
+
28
+ hash = Hash.new
29
+
30
+ @env.each do |variable, value|
31
+ keys = variable.to_s.split(separator)
32
+
33
+ next if keys.shift(prefix.size) != prefix
34
+
35
+ keys.map! { |key|
36
+ case converter
37
+ when :downcase then
38
+ key.downcase
39
+ when nil then
40
+ key
41
+ else
42
+ raise "Invalid ENV variables name converter: #{converter}"
43
+ end
44
+ }
45
+
46
+ leaf = keys[0...-1].inject(hash) { |h, key|
47
+ h[key] ||= {}
48
+ }
49
+
50
+ unless leaf.is_a?(Hash)
51
+ conflicting_key = (prefix + keys[0...-1]).join(separator)
52
+ raise "Environment variable #{variable} conflicts with variable #{conflicting_key}"
53
+ end
54
+
55
+ leaf[keys.last] = parse_values ? __value(value) : value
56
+ end
57
+
58
+ parse_arrays ? convert_hashes_to_arrays(hash) : hash
59
+ end
60
+
61
+ private
62
+ def convert_hashes_to_arrays(hash)
63
+ hash.each_with_object({}) do |(key, value), new_hash|
64
+ if value.is_a?(Hash)
65
+ value = convert_hashes_to_arrays(value)
66
+ if consecutive_numeric_keys?(value.keys)
67
+ new_hash[key] = value.keys.sort_by(&:to_i).map { |k| value[k] }
68
+ else
69
+ new_hash[key] = value
70
+ end
71
+ else
72
+ new_hash[key] = value
73
+ end
74
+ end
75
+ end
76
+
77
+ def consecutive_numeric_keys?(keys)
78
+ keys.map(&:to_i).sort == (0...keys.size).to_a && keys.all? { |k| k == k.to_i.to_s }
79
+ end
80
+
81
+ # Try to convert string to a correct type
82
+ def __value(v)
83
+ case v
84
+ when 'false'
85
+ false
86
+ when 'true'
87
+ true
88
+ else
89
+ Integer(v) rescue Float(v) rescue v
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,16 @@
1
+ module Config
2
+ module Sources
3
+ class HashSource
4
+ attr_accessor :hash
5
+
6
+ def initialize(hash)
7
+ @hash = hash
8
+ end
9
+
10
+ # returns hash that was passed in to initialize
11
+ def load
12
+ hash.is_a?(Hash) ? hash : {}
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,32 @@
1
+ require 'yaml'
2
+ require 'erb'
3
+
4
+ module Config
5
+ module Sources
6
+ class YAMLSource
7
+ attr_accessor :path
8
+ attr_reader :evaluate_erb
9
+
10
+ def initialize(path, evaluate_erb: Config.evaluate_erb_in_yaml)
11
+ @path = path.to_s
12
+ @evaluate_erb = !!evaluate_erb
13
+ end
14
+
15
+ # returns a config hash from the YML file
16
+ def load
17
+ if @path and File.exist?(@path)
18
+ file_contents = File.read(@path)
19
+ file_contents = ERB.new(file_contents).result if evaluate_erb
20
+ result = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(file_contents) : YAML.load(file_contents)
21
+ end
22
+
23
+ result || {}
24
+
25
+ rescue Psych::SyntaxError => e
26
+ raise "YAML syntax error occurred while parsing #{@path}. " \
27
+ "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
28
+ "Error: #{e.message}"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,7 @@
1
+ require 'config/integrations/heroku'
2
+
3
+ namespace 'config' do
4
+ task :heroku, [:app] => :environment do |_, args|
5
+ Config::Integrations::Heroku.new(args[:app]).invoke
6
+ end
7
+ end
@@ -0,0 +1,15 @@
1
+ require_relative "../error"
2
+
3
+ module Config
4
+ module Validation
5
+ class Error < ::Config::Error
6
+
7
+ def self.format(v_res)
8
+ v_res.errors.group_by(&:path).map do |path, messages|
9
+ "#{' ' * 2}#{path.join('.')}: #{messages.map(&:text).join('; ')}"
10
+ end.join("\n")
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ require_relative '../dry_validation_requirements'
2
+ require_relative '../error'
3
+
4
+ module Config
5
+ module Validation
6
+ module Schema
7
+ # Assigns schema configuration option
8
+ def schema=(value)
9
+ @schema = value
10
+ end
11
+
12
+ def schema(&block)
13
+ if block_given?
14
+ # Delay require until optional schema validation is requested
15
+ Config::DryValidationRequirements.load_dry_validation!
16
+ @schema = Dry::Schema.define(&block)
17
+ else
18
+ @schema
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,29 @@
1
+ require 'config/validation/error'
2
+
3
+ module Config
4
+ module Validation
5
+ module Validate
6
+ def validate!
7
+ return unless Config.validation_contract || Config.schema
8
+
9
+ Config::DryValidationRequirements.load_dry_validation!
10
+
11
+ validate_using!(Config.validation_contract)
12
+ validate_using!(Config.schema)
13
+ end
14
+
15
+ private
16
+
17
+ def validate_using!(validator)
18
+ if validator
19
+ result = validator.call(to_hash)
20
+
21
+ return if result.success?
22
+
23
+ error = Config::Validation::Error.format(result)
24
+ raise Config::Validation::Error, "Config validation failed:\n\n#{error}"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module Config
2
+ VERSION = '5.6.1'.freeze
3
+ end