sexy_settings 0.0.1 → 0.0.2

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: 3a2bdfde4cdce0f4675e616504f3116cb268696e
4
+ data.tar.gz: adcdd8d83a9fd898a2200d21f2c4d0dde34c08df
5
+ SHA512:
6
+ metadata.gz: 0a3be7f1002c585f6f6b3a105e1db74c9d4e743083cbc3ac42b53834abae9ee1b275901698adf7658c18d90d9b4d97e33ca88a84528ddc049b0e33a14d553978
7
+ data.tar.gz: 71f70a96e8f4666d3212e7ad0955c2f7840a45f783144c3d8f33ef900d41c5ec7118bab6fbabfbfac2ff034b0f3d9b094141fad5fa5ab382fb1eefb6ea3c0763
data/.gitignore CHANGED
@@ -3,3 +3,6 @@
3
3
  .bundle
4
4
  Gemfile.lock
5
5
  pkg/*
6
+ .byebug_history
7
+ .yardoc/
8
+ doc/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,23 @@
1
+ # See full list of defaults here: https://github.com/bbatsov/rubocop/blob/master/config/default.yml
2
+ # To see all cops used see here: https://github.com/bbatsov/rubocop/blob/master/config/enabled.yml
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 2.3
6
+
7
+ LineLength:
8
+ Max: 120
9
+
10
+ Style/CaseIndentation:
11
+ Enabled: false
12
+
13
+ Style/EmptyElse:
14
+ Enabled: false
15
+
16
+ Lint/AmbiguousRegexpLiteral:
17
+ Enabled: false
18
+
19
+ Style/CaseEquality:
20
+ Enabled: false
21
+
22
+ MethodLength:
23
+ Max: 30
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.10
5
+ - 2.2.5
6
+ - 2.3.1
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,14 @@
1
+ # Contributing to SexySettings
2
+
3
+ I love pull requests from everyone.
4
+
5
+ To contribute to SexySettings:
6
+
7
+ 1. Fork the [official repository](https://github.com/romikoops/sexy_settings/tree/master).
8
+ 2. Make your changes in a topic branch.
9
+ 3. Send a pull request.
10
+
11
+ Notes:
12
+
13
+ * Contributions without tests won't be accepted.
14
+ * Please don't update the Gem version.
data/Gemfile CHANGED
@@ -1,4 +1,9 @@
1
- source "http://rubygems.org"
1
+ # frozen_string_literal: true
2
+ source 'http://rubygems.org'
2
3
 
3
4
  # Specify your gem's dependencies in sexy_settings.gemspec
4
5
  gemspec
6
+
7
+ group :development do
8
+ gem 'rubocop'
9
+ end
data/LICENSE_MIT ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Roman Parashchenko
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,104 +1,136 @@
1
- # Sexy Settings
2
-
3
- Flexible specifying of application settings
4
-
5
- ## What is Sexy Settings?
6
-
7
- It is Ruby library for flexible specifying of application settings different ways:
8
-
9
- * from YAML file(default and custom settings)
10
- * from command line
11
-
12
- ### What's new in 0.0.1
13
-
14
- Init version with base functionality
15
-
16
- ## Getting Started
17
-
18
- ### Prerequisites
19
-
20
- It was tested with Ruby 1.9.2, but assumes it should work with other Ruby version as well
21
- ### Installation
22
-
23
- > gem install sexy_settings
24
-
25
- ### Configuration
26
-
27
- Create 2 configuration files, for default and custom settings. For instance,
28
-
29
- ```
30
- config\
31
- default.yaml
32
- overwritten.yaml
33
- ```
34
-
35
- Place next code to boot executable ruby file:
36
-
37
- ```ruby
38
- require 'sexy_settings'
39
-
40
- SexySettings.configure do |config|
41
- config.path_to_default_settings = File.expand_path("config.yaml", File.join(File.dirname(__FILE__), '..', 'config')) # 'default.yml' by default
42
- config.path_to_custom_settings = File.expand_path("overwritten.yaml", File.join(File.dirname(__FILE__), '..', 'config')) # 'custom.yml' by default
43
- config.path_to_project = File.dirname(__FILE__) # '.' by default
44
- config.env_variable_with_options = 'OPTIONS' # 'OPTS' by default
45
- cmd_line_option_delimiter = '$$$' # ',' by default
46
- end
47
- ```
48
-
49
- Specify shortcut method for Settings object:
50
-
51
- ```ruby
52
- def settings
53
- SexySettings::Base.instance()
54
- end
55
- ```
56
-
57
- ### Using
58
-
59
- There are 4 possible values of settings
60
- The priority ranks with respect to the setting places are as follows:
61
-
62
- > **command line** < **custom** < **default** < **nil**_(in case setting was not specified anywhere)_
63
-
64
- Thus, specifying some setting in command line will override the same setting value specified in <_default config file_> or <_custom config file_>
65
-
66
- Example:
67
-
68
- _default.yaml_
69
-
70
- ```yaml
71
- foo: bar
72
- foo1: default ${foo}
73
- foo2: default value
74
- ```
75
-
76
- _overwritten.yaml_
77
-
78
- ```yaml
79
- foo1: custom ${foo}
80
- ```
81
-
82
- Set environment variable:
83
-
84
- > OPTIONS="foo2=10$$$foo3=:hi$$$foo4=true"
85
-
86
- ```ruby
87
- puts settings.foo # returns 'bar'
88
- puts settings.foo1 # returns 'custom foo'
89
- puts settings.foo2 # returns 10
90
- puts settings.foo3 # returns :hi
91
- puts settings.foo4 # returns true
92
- ```
93
-
94
-
95
- ## Hints
96
-
97
- * Add <_default config file_> under version control system
98
- * Add <_custom config file_> to ignore list
99
- * Use command line with using Environment Variable for quick specifying setting in your Continuous Integration System
100
- * Use next code for output all settings as pretty formatted text:
101
-
102
- ```ruby
103
- puts settings.as_formatted_text
104
- ```
1
+ # Sexy Settings
2
+
3
+ [![Build Status](https://travis-ci.org/romikoops/sexy_settings.svg?branch=master)][travis]
4
+ [![Dependency Status](https://gemnasium.com/romikoops/sexy_settings.png)][gemnasium]
5
+
6
+ [travis]: https://travis-ci.org/romikoops/sexy_settings
7
+ [gemnasium]: https://gemnasium.com/romikoops/sexy_settings
8
+ (https://gemnasium.com/romikoops/sexy_settings)
9
+
10
+ Application settings are specified in a flexible way.
11
+
12
+ ## What is Sexy Settings?
13
+
14
+ It is a Ruby-based library used to specify application settings in different ways:
15
+
16
+ * Using the YAML file (default and custom settings).
17
+ * Using the command line.
18
+
19
+ ### What's new in 0.0.2
20
+
21
+ - Ability to override delimiter on fly for command line settings
22
+ - Hidden sensitive data in logging
23
+ - Changed default environment variable name with options
24
+
25
+ ## Getting Started
26
+
27
+ ### Prerequisites
28
+
29
+ It was tested with Ruby 2.0 but it expected to also work with other Ruby versions
30
+
31
+ ### Installation
32
+
33
+ > gem install sexy_settings
34
+
35
+ ### Configuration
36
+
37
+ Create 2 configuration files, one for default settings and the other one – for custom settings, e.g.:
38
+
39
+ ```
40
+ config\
41
+ default.yml
42
+ custom.yml
43
+ ```
44
+
45
+ Insert the following code to the boot executable ruby file:
46
+
47
+ ```ruby
48
+ require 'sexy_settings'
49
+ ```
50
+
51
+ Specify a shortcut method for the Settings object:
52
+
53
+ ```ruby
54
+ def settings
55
+ SexySettings::Base.instance
56
+ end
57
+ ```
58
+
59
+ ### Usage
60
+
61
+ There are 4 possible settings values. The priority ranks with respect to the settings location are as follows:
62
+
63
+
64
+ > **command line** < **custom** < **default** < **nil**_(in case setting was not specified anywhere)_
65
+
66
+ Thus, specifying some setting in the command line will override the same setting value specified in the <_default config file_> or <_custom config file_>
67
+
68
+ Example:
69
+
70
+ _default.yml_
71
+
72
+ ```yaml
73
+ foo: bar
74
+ foo1: default ${foo}
75
+ foo2: default value
76
+ ```
77
+
78
+ _custom.yml_
79
+
80
+ ```yaml
81
+ foo1: custom ${foo}
82
+ ```
83
+
84
+ Set an environment variable:
85
+
86
+ > SEXY_SETTINGS="foo2=10,foo3=:hi,foo4=true"
87
+
88
+ ```ruby
89
+ puts settings.foo # returns 'bar'
90
+ puts settings.foo1 # returns 'custom foo'
91
+ puts settings.foo2 # returns 10
92
+ puts settings.foo3 # returns :hi
93
+ puts settings.foo4 # returns true
94
+ ```
95
+
96
+
97
+ ## Hints
98
+
99
+ * Add <_default config file_> under the version control system.
100
+ * Add <_custom config file_> to ignore the list.
101
+ * Use the command line with an Environment Variable for fast specifying setting in your Continuous Integration System.
102
+ * Specify custom delimiter with SEXY_SETTINGS_DELIMITER environment variable in case you need unique delimiter for command line mode
103
+ * Use the following code to output all settings as a pretty formatted text:
104
+ ```ruby
105
+ puts settings.as_formatted_text
106
+ ```
107
+ __Note__, all sensitive data will be masked.
108
+
109
+ ## Advanced settings
110
+
111
+ You have ability to change some default settings:
112
+
113
+ ```ruby
114
+ SexySettings.configure do |config|
115
+ config.path_to_default_settings = File.expand_path("config.yaml", File.join(File.dirname(__FILE__), '..', 'config')) # 'default.yml' by default
116
+ config.path_to_custom_settings = File.expand_path("overwritten.yaml", File.join(File.dirname(__FILE__), '..', 'config')) # 'custom.yml' by default
117
+ config.path_to_project = File.dirname(__FILE__) # '.' by default
118
+ config.env_variable_with_options = 'OPTIONS' # 'SEXY_SETTINGS' by default
119
+ cmd_line_option_delimiter = '$$$' # ',' by default
120
+ end
121
+ ```
122
+
123
+ Contributing
124
+ ------------
125
+
126
+ Please see [CONTRIBUTING.md](https://github.com/romikoops/sexy_settings/blob/master/CONTRIBUTING.md).
127
+
128
+ SexySettings was originally designed and is now maintained by Roman Parashchenko. You can find list of contributors here [open source
129
+ community](https://github.com/romikoops/sexy_settings/graphs/contributors).
130
+
131
+ License
132
+ -------
133
+
134
+ SexySettngs is Copyright © 2011-2016 Roman Parashchenko. It is free
135
+ software, and may be redistributed under the terms specified in the
136
+ [LICENSE](/LICENSE_MIT) file.
data/Rakefile CHANGED
@@ -1,6 +1,18 @@
1
- require "bundler/gem_tasks"
1
+ # frozen_string_literal: true
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ Bundler.setup
2
5
 
3
- desc 'Spec all functionality of gem'
4
- task :spec_all do
5
- system("rspec spec/*/")
6
- end
6
+ require 'rake'
7
+ require 'yard'
8
+ require 'rspec/core/rake_task'
9
+ require 'rubocop/rake_task'
10
+
11
+ Bundler::GemHelper.install_tasks
12
+ RSpec::Core::RakeTask.new(:spec) { |_spec| }
13
+
14
+ YARD::Rake::YardocTask.new { |_t| }
15
+
16
+ RuboCop::RakeTask.new
17
+
18
+ task default: [:rubocop, :spec]
@@ -1,60 +1,39 @@
1
+ # frozen_string_literal: true
1
2
  require 'singleton'
2
3
  require 'yaml'
4
+ require_relative 'printable'
3
5
 
4
6
  module SexySettings
7
+ # This class represents core functionality
5
8
  class Base
6
- include Singleton
7
9
  attr_reader :default, :custom, :command_line, :all
8
10
 
11
+ include Singleton
12
+ include Printable
13
+
9
14
  # Priorities: command_line > custom.yml > default.yml > nil
10
15
  def initialize
11
- config = SexySettings.configuration
12
16
  @default = load_settings(config.path_to_default_settings)
13
17
  @custom = load_settings(config.path_to_custom_settings)
14
- @all = @default.merge(@custom)
15
- @command_line = {}
16
- unless ENV[config.env_variable_with_options].nil?
17
- ENV[config.env_variable_with_options].split(config.cmd_line_option_delimiter).each{|opt_line| parse_setting(opt_line) if opt_line }
18
- end
19
- @all.merge!(@command_line)
20
- @all.each_pair{|k, v| @all[k] = get_compound_value(v)}
21
- end
22
-
23
- def as_formatted_text(which=:all)
24
- props_list = case which
25
- when :all then @all
26
- when :custom then @custom
27
- when :default then @default
28
- else ''
29
- end.to_a
30
- max_key_size = props_list.map{|el| el.first.to_s.size}.max
31
- res = []
32
- title = "##{' '*20}#{which.to_s.capitalize} Settings#{' '*21}#"
33
- sharp_line = '#'*title.size
34
- res << sharp_line
35
- res << title
36
- res << sharp_line
37
- res << ''
38
- res += props_list.map{|el| "#{indent}#{el[0]}#{indent + indent(max_key_size - el[0].to_s.size)}=#{indent}#{el[1]}"}.sort
39
- res << ''
40
- res.join("\n")
18
+ init_command_line_settings
19
+ init_all_settings
41
20
  end
42
21
 
43
- private
22
+ private
44
23
 
45
- def load_settings(path)
46
- File.exists?(path) ? YAML::load_file(path) : {}
24
+ def config
25
+ SexySettings.configuration
47
26
  end
48
27
 
49
- def indent(space_count=nil)
50
- " "*(space_count.nil? ? 2 : space_count)
28
+ def load_settings(path)
29
+ File.exist?(path) ? YAML.load_file(path) : {}
51
30
  end
52
31
 
53
32
  # Parse the compound setting.
54
33
  # Parts of this config_parser must be defined earlier.
55
34
  # You can define an option as option=${another_option_name}/something
56
35
  def get_compound_value(value)
57
- if /\$\{(.*?)\}/.match(value.to_s)
36
+ if /\$\{(.*?)\}/ =~ value.to_s
58
37
  var = /\$\{(.*?)\}/.match(value.to_s)[1]
59
38
  exist_var = @all[var]
60
39
  raise ArgumentError, "Did you define this setting '#{var}' before?" if exist_var.nil?
@@ -66,7 +45,7 @@ module SexySettings
66
45
 
67
46
  def method_missing(name, *args)
68
47
  if name.to_s =~ /=$/
69
- @all[name.to_s] = args[0] if @all.has_key?(name.to_s)
48
+ @all[name.to_s] = args[0] if @all.key?(name.to_s)
70
49
  else
71
50
  @all[name.to_s]
72
51
  end
@@ -76,38 +55,65 @@ module SexySettings
76
55
  # Return the value as String if all tries have failed.
77
56
  # If the value is not of String type, return it as is.
78
57
  def try_convert_value(value)
79
- if value.class == String
80
- if /^[0-9]+$/.match(value) #int
81
- value.to_i
82
- elsif /^[0-9]+(\.)[0-9]*$/.match(value) #float
83
- value.to_f
84
- elsif (value.downcase == 'true') #boolean
85
- true
86
- elsif (value.downcase == 'false') #boolean
87
- false
88
- elsif /^:(.+)$/.match(value)
89
- $1.to_sym
90
- else
91
- value # can't parse, return String
92
- end
93
- else # value is not String, return it as is
94
- value
95
- end
58
+ return value.to_i if integer?(value)
59
+ return value.to_f if float?(value)
60
+ return true if boolean_true?(value)
61
+ return false if boolean_false?(value)
62
+ return convert_to_sym(value) if symbol?(value)
63
+ value # can't parse, return String
64
+ end
65
+
66
+ def integer?(value)
67
+ /^[0-9]+$/ =~ value
68
+ end
69
+
70
+ def float?(value)
71
+ /^[0-9]+(\.)[0-9]*$/ =~ value # float
72
+ end
73
+
74
+ def boolean_true?(value)
75
+ value.casecmp('true').zero?
76
+ end
77
+
78
+ def boolean_false?(value)
79
+ value.casecmp('false').zero? # boolean
80
+ end
81
+
82
+ def symbol?(value)
83
+ /^:(.+)$/ =~ value
84
+ end
85
+
86
+ def convert_to_sym(value)
87
+ /^:(.+)$/ =~ value && Regexp.last_match(1).to_sym
96
88
  end
97
89
 
98
90
  # Try to parse the setting's line
99
91
  # Delimiter is "=", ignores double quotes in the start and end positions
100
92
  def parse_setting(line)
101
- raise ArgumentError, "Invalid pair: #{line}. Expected: name=value" unless line["="]
93
+ raise ArgumentError, "Invalid pair: #{line}. Expected: name=value" unless line['=']
102
94
  param, value = line.split(/\s*=\s*/, 2)
103
- var_name = param.chomp.strip
104
95
  value = value.chomp.strip if value
105
96
  new_value = ''
106
- if (value)
107
- new_value = (value =~ /^["](.*)["]$/) ? $1 : value
97
+ if value
98
+ new_value = (value =~ /^["](.*)["]$/) ? Regexp.last_match(1) : value
108
99
  end
109
- new_value = try_convert_value(new_value)
110
- @command_line[var_name] = new_value
100
+ new_value = try_convert_value(new_value) if new_value.class == String
101
+ [param.chomp.strip, new_value]
102
+ end
103
+
104
+ def init_command_line_settings
105
+ @command_line = {}
106
+ data = ENV[config.env_variable_with_options]
107
+ return if data.nil?
108
+ delimiter = config.cmd_line_option_delimiter
109
+ data = data.split(delimiter).map { |el| parse_setting(el) if el }.compact
110
+ @command_line = Hash[data]
111
+ end
112
+
113
+ def init_all_settings
114
+ @all = @default.merge(@custom)
115
+ @all.merge!(@command_line)
116
+ @all.each_pair { |k, v| @all[k] = get_compound_value(v) }
111
117
  end
112
118
  end
113
- end
119
+ end
@@ -1,21 +1,37 @@
1
- module SexySettings
2
- class Configuration
3
- DEFAULT_OPTIONS = {
4
- :path_to_default_settings => "default.yml",
5
- :path_to_custom_settings => "custom.yml",
6
- :path_to_project => '.',
7
- :env_variable_with_options => 'OPTS',
8
- :cmd_line_option_delimiter => ','
9
- }
10
- DEFAULT_OPTIONS.keys.each{|option| attr_writer option}
11
-
12
- def initialize
13
- DEFAULT_OPTIONS.keys.each do |method|
14
- self.class.send(:define_method, method) do
15
- self.instance_variable_get("@#{method}") || DEFAULT_OPTIONS[method]
16
- end
17
- end
18
- end
19
-
20
- end
21
- end
1
+ # frozen_string_literal: true
2
+ module SexySettings
3
+ # This class holds all configuration settings
4
+ class Configuration
5
+ DEFAULT_OPTIONS = {
6
+ path_to_default_settings: 'default.yml',
7
+ path_to_custom_settings: 'custom.yml',
8
+ path_to_project: '.',
9
+ env_variable_with_options: 'SEXY_SETTINGS',
10
+ cmd_line_option_delimiter: ','
11
+ }.freeze
12
+
13
+ DEFAULT_OPTIONS.keys.each { |option| attr_writer option }
14
+
15
+ def cmd_line_option_delimiter
16
+ ENV['SEXY_SETTINGS_DELIMITER'] ||
17
+ @cmd_line_option_delimiter ||
18
+ DEFAULT_OPTIONS[:cmd_line_option_delimiter]
19
+ end
20
+
21
+ def path_to_default_settings
22
+ @path_to_default_settings || DEFAULT_OPTIONS[:path_to_default_settings]
23
+ end
24
+
25
+ def path_to_custom_settings
26
+ @path_to_custom_settings || DEFAULT_OPTIONS[:path_to_custom_settings]
27
+ end
28
+
29
+ def path_to_project
30
+ @path_to_project || DEFAULT_OPTIONS[:path_to_project]
31
+ end
32
+
33
+ def env_variable_with_options
34
+ @env_variable_with_options || DEFAULT_OPTIONS[:env_variable_with_options]
35
+ end
36
+ end
37
+ end
@@ -1,27 +1,30 @@
1
- module SexySettings
2
- # Used internally to ensure examples get reloaded between multiple runs in
3
- # the same process.
4
- def self.reset
5
- self.configuration.class::DEFAULT_OPTIONS.keys.each{|key| self.configuration.send("#{key}=", nil)}
6
- end
7
-
8
- # Returns the global configuration object
9
- def self.configuration
10
- @configuration ||= SexySettings::Configuration.new
11
- end
12
-
13
- # Yields the global configuration object
14
- #
15
- # == Examples
16
- #
17
- # SexySettings.configure do |config|
18
- # config.env_variable_with_options = 'OPTIONS'
19
- # end
20
- def self.configure
21
- if block_given?
22
- yield configuration
23
- else
24
- self.configuration
25
- end
26
- end
27
- end
1
+ # frozen_string_literal: true
2
+
3
+ # Core module
4
+ module SexySettings
5
+ # Used internally to ensure examples get reloaded between multiple runs in
6
+ # the same process.
7
+ def self.reset
8
+ configuration.class::DEFAULT_OPTIONS.keys.each { |key| configuration.send("#{key}=", nil) }
9
+ end
10
+
11
+ # Returns the global configuration object
12
+ def self.configuration
13
+ @configuration ||= SexySettings::Configuration.new
14
+ end
15
+
16
+ # Yields the global configuration object
17
+ #
18
+ # == Examples
19
+ #
20
+ # SexySettings.configure do |config|
21
+ # config.env_variable_with_options = 'OPTIONS'
22
+ # end
23
+ def self.configure
24
+ if block_given?
25
+ yield configuration
26
+ else
27
+ configuration
28
+ end
29
+ end
30
+ end