process_settings 0.13.3.pre.1 → 0.15.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5deb78cad7b19dfbdf5690d0c141a99281b9acb76d83afb1b3a3c4462d9be0d1
4
- data.tar.gz: 195cd80b52702c33e97533447022148a33d7c03e6c7525654d86bf71298a45c1
3
+ metadata.gz: 37586770d262584d6b5f6b2b4a8a7824eb351d9da15d6577dc0591223c0074f0
4
+ data.tar.gz: 8c61aa64d76749381c1311f7c08f2778a0c99134778c09d45aebd32d1ca10ff5
5
5
  SHA512:
6
- metadata.gz: 43e042004e010c603b3bb63c55ab9e00dd7ef52809ecf5c7da7abac83a5a82c9ec6f15de118c051f737ba1aaeb0990bb8111cf6c1f31ceabcfc60c2c78f3f520
7
- data.tar.gz: 2adf52ea2cd89a9d675aee0304b0cc5bdadae7ceabe3b5093d88830f20f70f4ecb61f720f34c5e5f97fad46a7bb9339ff0e3c4e076435e744d5d8cac97be2f5f
6
+ metadata.gz: 212169ce11e8ce4c15f056ffc14c15de1e46fadbc93878c922a577b44217bc8c84d3ecfa49773580bbbf06bdae4cb9a58caf55e570c334282e14ed26c9045ff6
7
+ data.tar.gz: 7afc6259634fba9c6a8e0ebe63ab4ffa361c79fdfb5dde63d4f39168222cb790cfa706989e43eaee5ea7b0f9625d393f4411b673bff68e11e0e609c694372adc
data/README.md CHANGED
@@ -169,8 +169,8 @@ The settings YAML files are always combined in alphabetical order by file path.
169
169
 
170
170
  ### Testing
171
171
  For testing, it is often necessary to set a specific override hash for the process_settings values to use in
172
- that use case. The `ProcessSettings::Testing::Helpers` module is provided for this purpose. It can be used to
173
- override a specific hash of process settings, while leaving the rest intact, and resetting back to the defaults
172
+ that use case. The `ProcessSettings::Testing::RSpec::Helpers` and `ProcessSettings::Testing::Minitest::Helpers` modules are provided for this purpose.
173
+ They can be used to override a specific hash of process settings, while leaving the rest intact, and resetting back to the defaults
174
174
  after the test case is over. Here are some examples using various testing frameworks:
175
175
 
176
176
  #### RSpec
@@ -181,7 +181,7 @@ require 'process_settings/testing/helpers'
181
181
  RSpec.configure do |config|
182
182
  # ...
183
183
 
184
- include ProcessSettings::Testing::Helpers
184
+ config.include ProcessSettings::Testing::RSpec::Helpers
185
185
 
186
186
  # Note: the include above will automatically register a global after block that will reset process_settings to their initial values.
187
187
  # ...
@@ -206,7 +206,7 @@ end
206
206
  require 'process_settings/testing/helpers'
207
207
 
208
208
  context SomeClass do
209
- include ProcessSettings::Testing::Helpers
209
+ include ProcessSettings::Testing::Minitest::Helpers
210
210
 
211
211
  # Note: the include above will automatically register a teardown block that will reset process_settings to their initial values.
212
212
 
@@ -77,11 +77,11 @@ end
77
77
 
78
78
  MINIMUM_LIBYAML_VERSION = '0.2.5' # So that null (nil) values don't have trailing spaces.
79
79
 
80
- def check_libyaml_version
80
+ def warn_if_old_libyaml_version
81
81
  if Gem::Version.new(Psych::LIBYAML_VERSION) < Gem::Version.new(MINIMUM_LIBYAML_VERSION)
82
82
  warn <<~EOS
83
83
 
84
- #{PROGRAM_NAME} error: libyaml version #{Psych::LIBYAML_VERSION} must be at least #{MINIMUM_LIBYAML_VERSION}. Try:
84
+ #{PROGRAM_NAME} warning: libyaml version #{Psych::LIBYAML_VERSION} is out of date; it should be at least #{MINIMUM_LIBYAML_VERSION}. On a Mac, try:
85
85
 
86
86
  brew update && brew upgrade libyaml
87
87
 
@@ -89,11 +89,29 @@ def check_libyaml_version
89
89
 
90
90
  gem install psych -- --enable-bundled-libyaml
91
91
  EOS
92
-
93
- exit(1)
94
92
  end
95
93
  end
96
94
 
95
+ def settings_files_match?(filename_1, filename_2)
96
+ filename_1 && filename_2 &&
97
+ File.exist?(filename_1) && File.exist?(filename_2) &&
98
+ diff_process_settings(filename_1, filename_2)
99
+ end
100
+
101
+ def diff_process_settings(filename_1, filename_2)
102
+ system(<<~EOS)
103
+ bundle exec diff_process_settings --silent "#{filename_1}" "#{filename_2}"
104
+ EOS
105
+ status_code = $?.exitstatus
106
+ case status_code
107
+ when 0
108
+ true
109
+ when 1
110
+ false
111
+ else
112
+ raise "diff_process_settings failed with code #{status_code}"
113
+ end
114
+ end
97
115
 
98
116
  #
99
117
  # main
@@ -101,14 +119,14 @@ end
101
119
 
102
120
  options = parse_options(ARGV.dup)
103
121
 
104
- check_libyaml_version
122
+ warn_if_old_libyaml_version
105
123
 
106
124
  combined_settings = read_and_combine_settings(Pathname.new(options.root_folder) + SETTINGS_FOLDER)
107
125
 
108
126
  version_number = options.version || default_version_number(options.initial_filename)
109
127
  combined_settings << end_marker(version_number)
110
128
 
111
- yaml = combined_settings.to_yaml
129
+ yaml = combined_settings.to_yaml.gsub(/: $/, ':') # libyaml before 0.2.5 wrote trailing space for nil
112
130
  yaml_with_warning_comment = add_warning_comment(yaml, options.root_folder, PROGRAM_NAME, SETTINGS_FOLDER)
113
131
 
114
132
  output_filename = options.output_filename
@@ -117,14 +135,17 @@ tmp_output_filename = "#{output_filename}.tmp"
117
135
  system("rm -f #{tmp_output_filename}")
118
136
  File.write(tmp_output_filename, yaml_with_warning_comment)
119
137
 
120
- system(<<~EOS)
121
- if bundle exec diff_process_settings --silent #{tmp_output_filename} #{output_filename} ; then
122
- #{"echo #{options.root_folder}: unchanged;" if options.verbose}
123
- rm -f #{tmp_output_filename};
138
+ if settings_files_match?(options.initial_filename, tmp_output_filename)
139
+ if settings_files_match?(output_filename, tmp_output_filename)
140
+ puts "#{options.root_folder}: unchanged" if options.verbose
141
+ FileUtils.rm_f(tmp_output_filename)
124
142
  else
125
- #{"echo #{options.root_folder}: UPDATING;" if options.verbose}
126
- mv #{tmp_output_filename} #{output_filename};
127
- fi
128
- EOS
143
+ puts "#{options.root_folder}: UPDATING (changed now)" if options.verbose
144
+ FileUtils.mv(tmp_output_filename, output_filename)
145
+ end
146
+ else
147
+ puts "#{options.root_folder}: UPDATING (unchanged now, but changed from initial)" if options.verbose
148
+ FileUtils.mv(tmp_output_filename, output_filename)
149
+ end
129
150
 
130
151
  exit(0)
@@ -34,10 +34,7 @@ input_files =
34
34
  if path == '-'
35
35
  ''
36
36
  else
37
- unless File.exists?(path)
38
- warn "#{path} not found--must be a path to combined_process_settings.yml"
39
- exit 1
40
- end
37
+ File.exist?(path) or path = '/dev/null'
41
38
  "< #{path}"
42
39
  end
43
40
  end
@@ -11,14 +11,16 @@ module ProcessSettings
11
11
  OnChangeDeprecation = ActiveSupport::Deprecation.new('1.0', 'ProcessSettings::Monitor')
12
12
 
13
13
  class AbstractMonitor
14
+
14
15
  attr_reader :min_polling_seconds, :logger
15
- attr_reader :static_context, :statically_targeted_settings
16
+ attr_reader :static_context, :statically_targeted_settings, :full_context_cache
16
17
 
17
18
  def initialize(logger:)
18
19
  @logger = logger or raise ArgumentError, "logger must be not be nil"
19
20
  @on_change_callbacks = []
20
21
  @when_updated_blocks = Set.new
21
22
  @static_context = {}
23
+ @full_context_cache = {}
22
24
  end
23
25
 
24
26
  # This is the main entry point for looking up settings on the Monitor instance.
@@ -94,10 +96,20 @@ module ProcessSettings
94
96
  def targeted_value(*path, dynamic_context:, required: true)
95
97
  # Merging the static context in is necessary to make sure that the static context isn't shifting
96
98
  # this can be rather costly to do every time if the dynamic context is not changing
97
- # TODO: Warn in the case where dynamic context was attempting to change a static value
98
- # TODO: Cache the last used dynamic context as a potential optimization to avoid unnecessary deep merges
99
- # TECH-4402 was created to address these todos
100
- full_context = dynamic_context.deep_merge(static_context)
99
+
100
+ # Warn in the case where dynamic context was attempting to change a static value
101
+ changes = dynamic_context.each_with_object({}) do |(key, dynamic_value), result|
102
+ if static_context.has_key?(key)
103
+ static_value = static_context[key]
104
+ if static_value != dynamic_value
105
+ result[key] = [static_value, dynamic_value]
106
+ end
107
+ end
108
+ end
109
+
110
+ changes.empty? or warn("WARNING: static context overwritten by dynamic!\n#{changes.inspect}")
111
+
112
+ full_context = full_context_from_cache(dynamic_context)
101
113
  result = statically_targeted_settings.reduce(:not_found) do |latest_result, target_and_settings|
102
114
  # find last value from matching targets
103
115
  if target_and_settings.target.target_key_matches?(full_context)
@@ -119,6 +131,22 @@ module ProcessSettings
119
131
  end
120
132
  end
121
133
 
134
+ def full_context_from_cache(dynamic_context)
135
+ if (full_context = full_context_cache[dynamic_context])
136
+ logger.info("cache hit ...")
137
+ full_context
138
+ else
139
+ logger.info("cache miss ...")
140
+ dynamic_context.deep_merge(static_context).tap do |full_context|
141
+ if full_context_cache.size <= 1000
142
+ full_context_cache[dynamic_context] = full_context
143
+ else
144
+ logger.info("cache limit reached ...")
145
+ end
146
+ end
147
+ end
148
+ end
149
+
122
150
  private
123
151
 
124
152
  class << self
@@ -8,47 +8,66 @@ require 'process_settings/testing/monitor'
8
8
 
9
9
  module ProcessSettings
10
10
  module Testing
11
- module Helpers
12
- class << self
13
- def included(including_klass)
14
- if including_klass.respond_to?(:after) # rspec
11
+ module Base
12
+ module Helpers
13
+ # Adds the given settings_hash as an override at the end of the process_settings array, with default targeting (true).
14
+ # Therefore this will override these settings while leaving others alone.
15
+ #
16
+ # @param [Hash] settings_hash
17
+ #
18
+ # @return none
19
+ def stub_process_settings(settings_hash)
20
+ new_target_and_settings = ProcessSettings::TargetAndSettings.new(
21
+ '<test_override>',
22
+ Target::true_target,
23
+ ProcessSettings::Settings.new(settings_hash.deep_stringify_keys)
24
+ )
25
+
26
+ new_process_settings = [
27
+ *initial_instance.statically_targeted_settings,
28
+ new_target_and_settings
29
+ ]
30
+
31
+ ProcessSettings.instance = ProcessSettings::Testing::Monitor.new(
32
+ new_process_settings,
33
+ logger: initial_instance.logger
34
+ )
35
+ end
36
+
37
+ def initial_instance
38
+ @initial_instance ||= ProcessSettings.instance
39
+ end
40
+ end
41
+ end
42
+
43
+ module RSpec
44
+ module Helpers
45
+ include Base::Helpers
46
+
47
+ class << self
48
+ def included(including_klass)
15
49
  including_klass.after do
16
50
  ProcessSettings.instance = initial_instance
17
51
  end
18
- else # minitest
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ module Minitest
58
+ module Helpers
59
+ include Base::Helpers
60
+
61
+ class << self
62
+ def included(including_klass)
19
63
  including_klass.define_method(:teardown) do
20
64
  ProcessSettings.instance = initial_instance
21
65
  end
22
66
  end
23
67
  end
24
68
  end
25
- # Adds the given settings_hash as an override at the end of the process_settings array, with default targeting (true).
26
- # Therefore this will override these settings while leaving others alone.
27
- #
28
- # @param [Hash] settings_hash
29
- #
30
- # @return none
31
- def stub_process_settings(settings_hash)
32
- new_target_and_settings = ProcessSettings::TargetAndSettings.new(
33
- '<test_override>',
34
- Target::true_target,
35
- ProcessSettings::Settings.new(settings_hash.deep_stringify_keys)
36
- )
37
-
38
- new_process_settings = [
39
- *initial_instance.statically_targeted_settings,
40
- new_target_and_settings
41
- ]
42
-
43
- ProcessSettings.instance = ProcessSettings::Testing::Monitor.new(
44
- new_process_settings,
45
- logger: initial_instance.logger
46
- )
47
- end
48
-
49
- def initial_instance
50
- @initial_instance ||= ProcessSettings.instance
51
- end
52
69
  end
70
+
71
+ Helpers = RSpec::Helpers # for backward-compatibility
53
72
  end
54
73
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ProcessSettings
4
- VERSION = '0.13.3.pre.1'
4
+ VERSION = '0.15.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: process_settings
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.3.pre.1
4
+ version: 0.15.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Invoca
@@ -122,9 +122,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
122
122
  version: '0'
123
123
  required_rubygems_version: !ruby/object:Gem::Requirement
124
124
  requirements:
125
- - - ">"
125
+ - - ">="
126
126
  - !ruby/object:Gem::Version
127
- version: 1.3.1
127
+ version: '0'
128
128
  requirements: []
129
129
  rubygems_version: 3.0.3
130
130
  signing_key: