sexy_settings 0.0.1 → 0.0.2

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