prefab-cloud-ruby 1.6.0 → 1.6.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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +4 -2
- data/CHANGELOG.md +5 -0
- data/Gemfile +1 -2
- data/Gemfile.lock +69 -82
- data/Rakefile +35 -32
- data/VERSION +1 -1
- data/dev/allocation_stats +60 -0
- data/dev/benchmark +40 -0
- data/lib/prefab/client.rb +3 -0
- data/lib/prefab/config_client.rb +2 -2
- data/lib/prefab/config_resolver.rb +5 -6
- data/lib/prefab/context.rb +90 -37
- data/lib/prefab/evaluation.rb +2 -1
- data/lib/prefab/options.rb +3 -3
- data/lib/prefab-cloud-ruby.rb +0 -1
- data/prefab-cloud-ruby.gemspec +6 -7
- data/test/support/common_helpers.rb +1 -1
- data/test/test_config_resolver.rb +41 -0
- data/test/test_context.rb +40 -44
- data/test/test_example_contexts_aggregator.rb +1 -4
- data/test/test_helper.rb +1 -1
- metadata +6 -19
- /data/{bin → dev}/console +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e0cc90e8b5acc15676a5101e6cbd902e37e38781ebb6d6fb33c892f938df3bbc
|
|
4
|
+
data.tar.gz: 68e1dbb144273aa9c54fb11efdf9333f2260a8805705d2aff47885719d995b7f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9518b4ab1b19e6f7532fd29146b26bd0fd4e3527dbc4fde041b61b712a843db95f6f9355d8afb0b2496436aab711ec5f4a57075dbaf80c7afd4bb85c35d92b53
|
|
7
|
+
data.tar.gz: d2f4806025b4c965792653149ac9976b47ed4f687bbbb9b73cf58af091a55d4ad03affe49e6cd55aba132fa1a49f422f73900a2d295abb3afb2867cf204bb533
|
data/.github/workflows/ruby.yml
CHANGED
|
@@ -22,7 +22,7 @@ jobs:
|
|
|
22
22
|
runs-on: ubuntu-latest
|
|
23
23
|
strategy:
|
|
24
24
|
matrix:
|
|
25
|
-
ruby-version: ['2.7', '3.0', '3.
|
|
25
|
+
ruby-version: ['2.7', '3.0', '3.3']
|
|
26
26
|
|
|
27
27
|
steps:
|
|
28
28
|
- uses: actions/checkout@v3
|
|
@@ -36,7 +36,9 @@ jobs:
|
|
|
36
36
|
uses: ruby/setup-ruby@v1
|
|
37
37
|
with:
|
|
38
38
|
ruby-version: ${{ matrix.ruby-version }}
|
|
39
|
-
bundler-cache:
|
|
39
|
+
bundler-cache: false # runs 'bundle install' and caches installed gems automatically
|
|
40
|
+
- name: Install dependencies
|
|
41
|
+
run: bundle install --without development --jobs 4 --retry 3
|
|
40
42
|
- name: Run tests
|
|
41
43
|
run: bundle exec rake
|
|
42
44
|
env:
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,23 +1,7 @@
|
|
|
1
1
|
GEM
|
|
2
2
|
remote: https://rubygems.org/
|
|
3
3
|
specs:
|
|
4
|
-
|
|
5
|
-
actionview (= 7.1.2)
|
|
6
|
-
activesupport (= 7.1.2)
|
|
7
|
-
nokogiri (>= 1.8.5)
|
|
8
|
-
racc
|
|
9
|
-
rack (>= 2.2.4)
|
|
10
|
-
rack-session (>= 1.0.1)
|
|
11
|
-
rack-test (>= 0.6.3)
|
|
12
|
-
rails-dom-testing (~> 2.2)
|
|
13
|
-
rails-html-sanitizer (~> 1.6)
|
|
14
|
-
actionview (7.1.2)
|
|
15
|
-
activesupport (= 7.1.2)
|
|
16
|
-
builder (~> 3.1)
|
|
17
|
-
erubi (~> 1.11)
|
|
18
|
-
rails-dom-testing (~> 2.2)
|
|
19
|
-
rails-html-sanitizer (~> 1.6)
|
|
20
|
-
activesupport (7.1.2)
|
|
4
|
+
activesupport (7.1.3.2)
|
|
21
5
|
base64
|
|
22
6
|
bigdecimal
|
|
23
7
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
@@ -27,34 +11,48 @@ GEM
|
|
|
27
11
|
minitest (>= 5.1)
|
|
28
12
|
mutex_m
|
|
29
13
|
tzinfo (~> 2.0)
|
|
30
|
-
addressable (2.8.
|
|
31
|
-
public_suffix (>= 2.0.2, <
|
|
14
|
+
addressable (2.8.6)
|
|
15
|
+
public_suffix (>= 2.0.2, < 6.0)
|
|
32
16
|
ansi (1.5.0)
|
|
33
17
|
base64 (0.2.0)
|
|
34
|
-
benchmark-ips (2.
|
|
35
|
-
bigdecimal (3.1.
|
|
18
|
+
benchmark-ips (2.13.0)
|
|
19
|
+
bigdecimal (3.1.7)
|
|
36
20
|
builder (3.2.4)
|
|
37
|
-
concurrent-ruby (1.
|
|
21
|
+
concurrent-ruby (1.2.3)
|
|
38
22
|
connection_pool (2.4.1)
|
|
39
|
-
crass (1.0.6)
|
|
40
23
|
descendants_tracker (0.0.4)
|
|
41
24
|
thread_safe (~> 0.3, >= 0.3.1)
|
|
42
|
-
docile (1.
|
|
43
|
-
domain_name (0.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
25
|
+
docile (1.4.0)
|
|
26
|
+
domain_name (0.6.20240107)
|
|
27
|
+
drb (2.2.1)
|
|
28
|
+
faraday (1.10.3)
|
|
29
|
+
faraday-em_http (~> 1.0)
|
|
30
|
+
faraday-em_synchrony (~> 1.0)
|
|
31
|
+
faraday-excon (~> 1.1)
|
|
32
|
+
faraday-httpclient (~> 1.0)
|
|
33
|
+
faraday-multipart (~> 1.0)
|
|
49
34
|
faraday-net_http (~> 1.0)
|
|
50
|
-
|
|
51
|
-
|
|
35
|
+
faraday-net_http_persistent (~> 1.0)
|
|
36
|
+
faraday-patron (~> 1.0)
|
|
37
|
+
faraday-rack (~> 1.0)
|
|
38
|
+
faraday-retry (~> 1.0)
|
|
39
|
+
ruby2_keywords (>= 0.0.4)
|
|
40
|
+
faraday-em_http (1.0.0)
|
|
41
|
+
faraday-em_synchrony (1.0.0)
|
|
42
|
+
faraday-excon (1.1.0)
|
|
43
|
+
faraday-httpclient (1.0.1)
|
|
44
|
+
faraday-multipart (1.0.4)
|
|
45
|
+
multipart-post (~> 2)
|
|
52
46
|
faraday-net_http (1.0.1)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
47
|
+
faraday-net_http_persistent (1.2.0)
|
|
48
|
+
faraday-patron (1.0.0)
|
|
49
|
+
faraday-rack (1.0.0)
|
|
50
|
+
faraday-retry (1.0.3)
|
|
51
|
+
ffi (1.16.3)
|
|
52
|
+
ffi-compiler (1.3.2)
|
|
53
|
+
ffi (>= 1.15.5)
|
|
56
54
|
rake
|
|
57
|
-
git (1.
|
|
55
|
+
git (1.19.1)
|
|
58
56
|
addressable (~> 2.8)
|
|
59
57
|
rchardet (~> 1.8)
|
|
60
58
|
github_api (0.19.0)
|
|
@@ -63,20 +61,21 @@ GEM
|
|
|
63
61
|
faraday (>= 0.8, < 2)
|
|
64
62
|
hashie (~> 3.5, >= 3.5.2)
|
|
65
63
|
oauth2 (~> 1.0)
|
|
66
|
-
google-protobuf (3.
|
|
67
|
-
googleapis-common-protos-types (1.
|
|
68
|
-
google-protobuf (~> 3.
|
|
64
|
+
google-protobuf (3.25.3)
|
|
65
|
+
googleapis-common-protos-types (1.14.0)
|
|
66
|
+
google-protobuf (~> 3.18)
|
|
69
67
|
hashie (3.6.0)
|
|
70
|
-
highline (
|
|
71
|
-
http (5.0
|
|
72
|
-
addressable (~> 2.
|
|
68
|
+
highline (3.0.1)
|
|
69
|
+
http (5.2.0)
|
|
70
|
+
addressable (~> 2.8)
|
|
71
|
+
base64 (~> 0.1)
|
|
73
72
|
http-cookie (~> 1.0)
|
|
74
73
|
http-form_data (~> 2.2)
|
|
75
|
-
llhttp-ffi (~> 0.
|
|
76
|
-
http-cookie (1.0.
|
|
74
|
+
llhttp-ffi (~> 0.5.0)
|
|
75
|
+
http-cookie (1.0.5)
|
|
77
76
|
domain_name (~> 0.5)
|
|
78
77
|
http-form_data (2.3.0)
|
|
79
|
-
i18n (1.14.
|
|
78
|
+
i18n (1.14.4)
|
|
80
79
|
concurrent-ruby (~> 1.0)
|
|
81
80
|
juwelier (2.4.9)
|
|
82
81
|
builder
|
|
@@ -90,34 +89,32 @@ GEM
|
|
|
90
89
|
rake
|
|
91
90
|
rdoc
|
|
92
91
|
semver2
|
|
93
|
-
jwt (2.
|
|
92
|
+
jwt (2.8.1)
|
|
93
|
+
base64
|
|
94
94
|
kamelcase (0.0.2)
|
|
95
95
|
semver2 (~> 3)
|
|
96
|
-
ld-eventsource (2.2.
|
|
96
|
+
ld-eventsource (2.2.2)
|
|
97
97
|
concurrent-ruby (~> 1.0)
|
|
98
98
|
http (>= 4.4.1, < 6.0.0)
|
|
99
|
-
llhttp-ffi (0.
|
|
99
|
+
llhttp-ffi (0.5.0)
|
|
100
100
|
ffi-compiler (~> 1.0)
|
|
101
101
|
rake (~> 13.0)
|
|
102
|
-
loofah (2.21.4)
|
|
103
|
-
crass (~> 1.0.2)
|
|
104
|
-
nokogiri (>= 1.12.0)
|
|
105
102
|
macaddr (1.7.2)
|
|
106
103
|
systemu (~> 2.6.5)
|
|
107
|
-
mini_portile2 (2.8.
|
|
108
|
-
minitest (5.
|
|
109
|
-
minitest-focus (1.
|
|
104
|
+
mini_portile2 (2.8.5)
|
|
105
|
+
minitest (5.22.3)
|
|
106
|
+
minitest-focus (1.4.0)
|
|
110
107
|
minitest (>= 4, < 6)
|
|
111
|
-
minitest-reporters (1.
|
|
108
|
+
minitest-reporters (1.6.1)
|
|
112
109
|
ansi
|
|
113
110
|
builder
|
|
114
111
|
minitest (>= 5.0)
|
|
115
112
|
ruby-progressbar
|
|
116
113
|
multi_json (1.15.0)
|
|
117
114
|
multi_xml (0.6.0)
|
|
118
|
-
multipart-post (2.
|
|
115
|
+
multipart-post (2.4.0)
|
|
119
116
|
mutex_m (0.2.0)
|
|
120
|
-
nokogiri (1.
|
|
117
|
+
nokogiri (1.16.3)
|
|
121
118
|
mini_portile2 (~> 2.8.2)
|
|
122
119
|
racc (~> 1.4)
|
|
123
120
|
oauth2 (1.4.11)
|
|
@@ -126,41 +123,32 @@ GEM
|
|
|
126
123
|
multi_json (~> 1.3)
|
|
127
124
|
multi_xml (~> 0.5)
|
|
128
125
|
rack (>= 1.2, < 4)
|
|
129
|
-
psych (
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
rack
|
|
134
|
-
|
|
135
|
-
rack-test (2.1.0)
|
|
136
|
-
rack (>= 1.3)
|
|
137
|
-
rails-dom-testing (2.2.0)
|
|
138
|
-
activesupport (>= 5.0.0)
|
|
139
|
-
minitest
|
|
140
|
-
nokogiri (>= 1.6)
|
|
141
|
-
rails-html-sanitizer (1.6.0)
|
|
142
|
-
loofah (~> 2.21)
|
|
143
|
-
nokogiri (~> 1.14)
|
|
144
|
-
rake (13.0.6)
|
|
126
|
+
psych (5.1.2)
|
|
127
|
+
stringio
|
|
128
|
+
public_suffix (5.0.4)
|
|
129
|
+
racc (1.7.3)
|
|
130
|
+
rack (3.0.10)
|
|
131
|
+
rake (13.1.0)
|
|
145
132
|
rchardet (1.8.0)
|
|
146
|
-
rdoc (6.3.
|
|
147
|
-
|
|
148
|
-
|
|
133
|
+
rdoc (6.6.3.1)
|
|
134
|
+
psych (>= 4.0.0)
|
|
135
|
+
ruby-progressbar (1.13.0)
|
|
136
|
+
ruby2_keywords (0.0.5)
|
|
149
137
|
semantic_logger (4.15.0)
|
|
150
138
|
concurrent-ruby (~> 1.0)
|
|
151
139
|
semver2 (3.4.2)
|
|
152
|
-
simplecov (0.
|
|
140
|
+
simplecov (0.22.0)
|
|
153
141
|
docile (~> 1.1)
|
|
154
142
|
simplecov-html (~> 0.11)
|
|
143
|
+
simplecov_json_formatter (~> 0.1)
|
|
155
144
|
simplecov-html (0.12.3)
|
|
145
|
+
simplecov_json_formatter (0.1.4)
|
|
146
|
+
stringio (3.1.0)
|
|
156
147
|
systemu (2.6.5)
|
|
157
148
|
thread_safe (0.3.6)
|
|
158
|
-
timecop (0.9.
|
|
149
|
+
timecop (0.9.8)
|
|
159
150
|
tzinfo (2.0.6)
|
|
160
151
|
concurrent-ruby (~> 1.0)
|
|
161
|
-
unf (0.1.4)
|
|
162
|
-
unf_ext
|
|
163
|
-
unf_ext (0.0.8)
|
|
164
152
|
uuid (2.3.9)
|
|
165
153
|
macaddr (~> 1.0)
|
|
166
154
|
|
|
@@ -168,7 +156,6 @@ PLATFORMS
|
|
|
168
156
|
ruby
|
|
169
157
|
|
|
170
158
|
DEPENDENCIES
|
|
171
|
-
actionpack (>= 4)
|
|
172
159
|
activesupport (>= 4)
|
|
173
160
|
benchmark-ips
|
|
174
161
|
bundler
|
data/Rakefile
CHANGED
|
@@ -9,42 +9,45 @@ rescue Bundler::BundlerError => e
|
|
|
9
9
|
warn 'Run `bundle install` to install missing gems'
|
|
10
10
|
exit e.status_code
|
|
11
11
|
end
|
|
12
|
+
|
|
12
13
|
require 'rake'
|
|
13
|
-
|
|
14
|
-
Juwelier::Tasks.new do |gem|
|
|
15
|
-
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
|
16
|
-
gem.name = 'prefab-cloud-ruby'
|
|
17
|
-
gem.homepage = 'http://github.com/prefab-cloud/prefab-cloud-ruby'
|
|
18
|
-
gem.license = 'MIT'
|
|
19
|
-
gem.summary = %(Prefab Ruby Infrastructure)
|
|
20
|
-
gem.description = %(Feature Flags, Live Config, and Dynamic Log Levels as a service)
|
|
21
|
-
gem.email = 'jdwyer@prefab.cloud'
|
|
22
|
-
gem.authors = ['Jeff Dwyer']
|
|
14
|
+
task default: :test
|
|
23
15
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Juwelier::
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
16
|
+
unless ENV['CI']
|
|
17
|
+
require 'juwelier'
|
|
18
|
+
Juwelier::Tasks.new do |gem|
|
|
19
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
|
20
|
+
gem.name = 'prefab-cloud-ruby'
|
|
21
|
+
gem.homepage = 'http://github.com/prefab-cloud/prefab-cloud-ruby'
|
|
22
|
+
gem.license = 'MIT'
|
|
23
|
+
gem.summary = %(Prefab Ruby Infrastructure)
|
|
24
|
+
gem.description = %(Feature Flags, Live Config, and Dynamic Log Levels as a service)
|
|
25
|
+
gem.email = 'jdwyer@prefab.cloud'
|
|
26
|
+
gem.authors = ['Jeff Dwyer']
|
|
33
27
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
28
|
+
# dependencies defined in Gemfile
|
|
29
|
+
end
|
|
30
|
+
Juwelier::RubygemsDotOrgTasks.new
|
|
31
|
+
require 'rake/testtask'
|
|
32
|
+
Rake::TestTask.new(:test) do |test|
|
|
33
|
+
test.libs << 'lib' << 'test'
|
|
34
|
+
test.pattern = 'test/**/test_*.rb'
|
|
35
|
+
test.verbose = true
|
|
36
|
+
end
|
|
39
37
|
|
|
40
|
-
|
|
38
|
+
desc 'Code coverage detail'
|
|
39
|
+
task :simplecov do
|
|
40
|
+
ENV['COVERAGE'] = 'true'
|
|
41
|
+
Rake::Task['test'].execute
|
|
42
|
+
end
|
|
41
43
|
|
|
42
|
-
require 'rdoc/task'
|
|
43
|
-
Rake::RDocTask.new do |rdoc|
|
|
44
|
-
|
|
44
|
+
require 'rdoc/task'
|
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
|
46
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ''
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
49
|
+
rdoc.title = "prefab-cloud-ruby #{version}"
|
|
50
|
+
rdoc.rdoc_files.include('README*')
|
|
51
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
52
|
+
end
|
|
50
53
|
end
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.6.
|
|
1
|
+
1.6.1
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
|
|
6
|
+
gemspec = Dir.glob(File.expand_path("../../*.gemspec", __FILE__)).first
|
|
7
|
+
spec = Gem::Specification.load(gemspec)
|
|
8
|
+
|
|
9
|
+
# Add the require paths to the $LOAD_PATH
|
|
10
|
+
spec.require_paths.each do |path|
|
|
11
|
+
full_path = File.expand_path("../" + path, __dir__)
|
|
12
|
+
$LOAD_PATH.unshift(full_path) unless $LOAD_PATH.include?(full_path)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
spec.require_paths.each do |path|
|
|
16
|
+
require "./lib/prefab-cloud-ruby"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
require 'prefab-cloud-ruby'
|
|
20
|
+
|
|
21
|
+
$prefab = Prefab::Client.new(collect_logger_counts: false, collect_evaluation_summaries: false,
|
|
22
|
+
context_upload_mode: :none)
|
|
23
|
+
$prefab.get('prefab.auth.allowed_origins')
|
|
24
|
+
|
|
25
|
+
puts '-' * 80
|
|
26
|
+
|
|
27
|
+
require 'allocation_stats'
|
|
28
|
+
|
|
29
|
+
$runs = 100
|
|
30
|
+
|
|
31
|
+
def measure(description)
|
|
32
|
+
puts "Measuring #{description}..."
|
|
33
|
+
stats = $prefab.with_context(user: { email_suffix: 'yahoo.com' }) do
|
|
34
|
+
AllocationStats.trace do
|
|
35
|
+
$runs.times do
|
|
36
|
+
yield
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
allocations = stats.allocations(alias_paths: true).group_by(:sourcefile, :sourceline, :class)
|
|
42
|
+
|
|
43
|
+
if ENV['TOP']
|
|
44
|
+
puts allocations.sort_by_size.to_text.split("\n").first(20)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
puts "Total allocations: #{allocations.all.values.map(&:size).sum}"
|
|
48
|
+
puts "Total memory: #{allocations.all.values.flatten.map(&:memsize).sum}"
|
|
49
|
+
puts stats.gc_profiler_report
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
measure "no-JIT context (#{$runs} runs)" do
|
|
53
|
+
$prefab.get('prefab.auth.allowed_origins')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
puts "\n\n"
|
|
57
|
+
|
|
58
|
+
measure "with JIT context (#{$runs} runs)" do
|
|
59
|
+
$prefab.get('prefab.auth.allowed_origins', { a: { b: "c" } })
|
|
60
|
+
end
|
data/dev/benchmark
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
|
|
6
|
+
gemspec = Dir.glob(File.expand_path("../../*.gemspec", __FILE__)).first
|
|
7
|
+
spec = Gem::Specification.load(gemspec)
|
|
8
|
+
|
|
9
|
+
# Add the require paths to the $LOAD_PATH
|
|
10
|
+
spec.require_paths.each do |path|
|
|
11
|
+
full_path = File.expand_path("../" + path, __dir__)
|
|
12
|
+
$LOAD_PATH.unshift(full_path) unless $LOAD_PATH.include?(full_path)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
spec.require_paths.each do |path|
|
|
16
|
+
require "./lib/prefab-cloud-ruby"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
require 'prefab-cloud-ruby'
|
|
20
|
+
require 'benchmark/ips'
|
|
21
|
+
|
|
22
|
+
prefab = Prefab::Client.new(collect_logger_counts: false, collect_evaluation_summaries: false,
|
|
23
|
+
context_upload_mode: :none)
|
|
24
|
+
|
|
25
|
+
prefab.get('prefab.auth.allowed_origins')
|
|
26
|
+
|
|
27
|
+
prefab.with_context(user: { email_suffix: 'yahoo.com' }) do
|
|
28
|
+
Benchmark.ips do |x|
|
|
29
|
+
x.report("noop") do
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
x.report('prefab.get') do
|
|
33
|
+
prefab.get('prefab.auth.allowed_origins')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
x.report('prefab.get with jit context') do
|
|
37
|
+
prefab.get('prefab.auth.allowed_origins', { a: { b: "c" } })
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
data/lib/prefab/client.rb
CHANGED
data/lib/prefab/config_client.rb
CHANGED
|
@@ -60,7 +60,7 @@ module Prefab
|
|
|
60
60
|
@base_client.example_contexts_aggregator.record(context)
|
|
61
61
|
end
|
|
62
62
|
|
|
63
|
-
evaluation = _get(key,
|
|
63
|
+
evaluation = _get(key, properties)
|
|
64
64
|
|
|
65
65
|
@base_client.context_shape_aggregator&.push(context)
|
|
66
66
|
|
|
@@ -168,7 +168,7 @@ module Prefab
|
|
|
168
168
|
]
|
|
169
169
|
end.to_h
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
Prefab::Context.default_context = default_contexts || {}
|
|
172
172
|
|
|
173
173
|
configs.configs.each do |config|
|
|
174
174
|
@config_loader.set(config, source)
|
|
@@ -5,8 +5,6 @@ module Prefab
|
|
|
5
5
|
attr_accessor :project_env_id # this will be set by the config_client when it gets an API response
|
|
6
6
|
attr_reader :local_store
|
|
7
7
|
|
|
8
|
-
attr_accessor :default_context
|
|
9
|
-
|
|
10
8
|
def initialize(base_client, config_loader)
|
|
11
9
|
@lock = Concurrent::ReadWriteLock.new
|
|
12
10
|
@local_store = {}
|
|
@@ -14,7 +12,6 @@ module Prefab
|
|
|
14
12
|
@project_env_id = 0 # we don't know this yet, it is set from the API results
|
|
15
13
|
@base_client = base_client
|
|
16
14
|
@on_update = nil
|
|
17
|
-
@default_context = {}
|
|
18
15
|
make_local
|
|
19
16
|
end
|
|
20
17
|
|
|
@@ -59,11 +56,13 @@ module Prefab
|
|
|
59
56
|
end
|
|
60
57
|
|
|
61
58
|
def make_context(properties)
|
|
62
|
-
if properties
|
|
59
|
+
if properties.is_a?(Context)
|
|
60
|
+
properties
|
|
61
|
+
elsif properties == NO_DEFAULT_PROVIDED || properties.nil?
|
|
63
62
|
Context.current
|
|
64
63
|
else
|
|
65
|
-
Context.
|
|
66
|
-
end
|
|
64
|
+
Context.join(parent: Context.current, hash: properties, id: :jit)
|
|
65
|
+
end
|
|
67
66
|
end
|
|
68
67
|
|
|
69
68
|
private
|
data/lib/prefab/context.rb
CHANGED
|
@@ -8,18 +8,8 @@ module Prefab
|
|
|
8
8
|
attr_reader :name
|
|
9
9
|
|
|
10
10
|
def initialize(name, hash)
|
|
11
|
-
@hash = {}
|
|
12
11
|
@name = name.to_s
|
|
13
|
-
|
|
14
|
-
merge!(hash)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def get(parts)
|
|
18
|
-
@hash[parts]
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def merge!(other)
|
|
22
|
-
@hash = @hash.merge(other.transform_keys(&:to_s))
|
|
12
|
+
@hash = hash.transform_keys(&:to_s)
|
|
23
13
|
end
|
|
24
14
|
|
|
25
15
|
def to_h
|
|
@@ -27,13 +17,13 @@ module Prefab
|
|
|
27
17
|
end
|
|
28
18
|
|
|
29
19
|
def key
|
|
30
|
-
"#{@name}:#{
|
|
20
|
+
"#{@name}:#{@hash['key']}"
|
|
31
21
|
end
|
|
32
22
|
|
|
33
23
|
def to_proto
|
|
34
24
|
PrefabProto::Context.new(
|
|
35
25
|
type: name,
|
|
36
|
-
values:
|
|
26
|
+
values: @hash.transform_values do |value|
|
|
37
27
|
ConfigValueWrapper.wrap(value)
|
|
38
28
|
end
|
|
39
29
|
)
|
|
@@ -44,17 +34,35 @@ module Prefab
|
|
|
44
34
|
attr_reader :contexts, :seen_at
|
|
45
35
|
|
|
46
36
|
class << self
|
|
37
|
+
def global_context=(context)
|
|
38
|
+
@global_context = join(hash: context, parent: nil, id: :global_context)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def global_context
|
|
42
|
+
@global_context ||= join(parent: nil, id: :global_context)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def default_context=(context)
|
|
46
|
+
@default_context = join(hash: context, parent: global_context, id: :default_context)
|
|
47
|
+
|
|
48
|
+
self.current.update_parent(@default_context)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def default_context
|
|
52
|
+
@default_context ||= join(parent: global_context, id: :default_context)
|
|
53
|
+
end
|
|
54
|
+
|
|
47
55
|
def current=(context)
|
|
48
|
-
Thread.current[THREAD_KEY] = context
|
|
56
|
+
Thread.current[THREAD_KEY] = join(hash: context || {}, parent: default_context, id: :block)
|
|
49
57
|
end
|
|
50
58
|
|
|
51
59
|
def current
|
|
52
|
-
Thread.current[THREAD_KEY] ||=
|
|
60
|
+
Thread.current[THREAD_KEY] ||= join(parent: default_context, id: :block)
|
|
53
61
|
end
|
|
54
62
|
|
|
55
63
|
def with_context(context)
|
|
56
64
|
old_context = Thread.current[THREAD_KEY]
|
|
57
|
-
Thread.current[THREAD_KEY] =
|
|
65
|
+
Thread.current[THREAD_KEY] = join(parent: default_context, hash: context, id: :block)
|
|
58
66
|
yield
|
|
59
67
|
ensure
|
|
60
68
|
Thread.current[THREAD_KEY] = old_context
|
|
@@ -62,7 +70,7 @@ module Prefab
|
|
|
62
70
|
|
|
63
71
|
def with_merged_context(context)
|
|
64
72
|
old_context = Thread.current[THREAD_KEY]
|
|
65
|
-
Thread.current[THREAD_KEY] =
|
|
73
|
+
Thread.current[THREAD_KEY] = join(parent: current, hash: context, id: :merged)
|
|
66
74
|
yield
|
|
67
75
|
ensure
|
|
68
76
|
Thread.current[THREAD_KEY] = old_context
|
|
@@ -77,51 +85,92 @@ module Prefab
|
|
|
77
85
|
end
|
|
78
86
|
end
|
|
79
87
|
|
|
80
|
-
def
|
|
88
|
+
def self.join(hash: {}, parent: nil, id: :not_provided)
|
|
89
|
+
context = new(hash)
|
|
90
|
+
context.update_parent(parent)
|
|
91
|
+
context.instance_variable_set(:@id, id)
|
|
92
|
+
context
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def initialize(hash = {})
|
|
81
96
|
@contexts = {}
|
|
97
|
+
@flattened = {}
|
|
82
98
|
@seen_at = Time.now.utc.to_i
|
|
99
|
+
warned = false
|
|
100
|
+
|
|
101
|
+
if hash.is_a?(Hash)
|
|
102
|
+
hash.map do |name, values|
|
|
103
|
+
unless values.is_a?(Hash)
|
|
104
|
+
warn "[DEPRECATION] Prefab contexts should be a hash with a key of the context name and a value of a hash."
|
|
105
|
+
values = { name => values }
|
|
106
|
+
name = BLANK_CONTEXT_NAME
|
|
107
|
+
end
|
|
83
108
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
context.map do |name, values|
|
|
88
|
-
if values.is_a?(Hash)
|
|
89
|
-
@contexts[name.to_s] = NamedContext.new(name, values)
|
|
90
|
-
else
|
|
91
|
-
warn '[DEPRECATION] Prefab contexts should be a hash with a key of the context name and a value of a hash.'
|
|
92
|
-
|
|
93
|
-
@contexts[BLANK_CONTEXT_NAME] ||= NamedContext.new(BLANK_CONTEXT_NAME, {})
|
|
94
|
-
@contexts[BLANK_CONTEXT_NAME].merge!({ name => values })
|
|
109
|
+
@contexts[name.to_s] = NamedContext.new(name, values)
|
|
110
|
+
values.each do |key, value|
|
|
111
|
+
@flattened[name.to_s + '.' + key.to_s] = value
|
|
95
112
|
end
|
|
96
113
|
end
|
|
97
114
|
else
|
|
98
|
-
raise ArgumentError, 'must be a Hash
|
|
115
|
+
raise ArgumentError, 'must be a Hash'
|
|
99
116
|
end
|
|
100
117
|
end
|
|
101
118
|
|
|
119
|
+
def update_parent(parent)
|
|
120
|
+
@parent = parent
|
|
121
|
+
end
|
|
122
|
+
|
|
102
123
|
def blank?
|
|
103
124
|
contexts.empty?
|
|
104
125
|
end
|
|
105
126
|
|
|
106
127
|
def set(name, hash)
|
|
107
128
|
@contexts[name.to_s] = NamedContext.new(name, hash)
|
|
129
|
+
hash.each do |key, value|
|
|
130
|
+
@flattened[name.to_s + '.' + key.to_s] = value
|
|
131
|
+
end
|
|
108
132
|
end
|
|
109
133
|
|
|
110
|
-
def get(property_key)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if key.nil?
|
|
114
|
-
name = BLANK_CONTEXT_NAME
|
|
115
|
-
key = property_key
|
|
134
|
+
def get(property_key, scope: nil)
|
|
135
|
+
if !property_key.include?(".")
|
|
136
|
+
property_key = BLANK_CONTEXT_NAME + '.' + property_key
|
|
116
137
|
end
|
|
117
138
|
|
|
118
|
-
|
|
139
|
+
if @flattened.key?(property_key)
|
|
140
|
+
@flattened[property_key]
|
|
141
|
+
else
|
|
142
|
+
scope ||= property_key.split('.').first
|
|
143
|
+
|
|
144
|
+
if @contexts[scope]
|
|
145
|
+
# If the key is in the present scope, parent values should not be used.
|
|
146
|
+
# We can consider the parent value clobbered by the present scope.
|
|
147
|
+
nil
|
|
148
|
+
else
|
|
149
|
+
@parent&.get(property_key, scope: scope)
|
|
150
|
+
end
|
|
151
|
+
end
|
|
119
152
|
end
|
|
120
153
|
|
|
121
154
|
def to_h
|
|
122
155
|
contexts.transform_values(&:to_h)
|
|
123
156
|
end
|
|
124
157
|
|
|
158
|
+
def to_s
|
|
159
|
+
"#<Prefab::Context:#{object_id} id=#{@id} #{to_h}>"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# Visualize a tree of the context up through its parents
|
|
163
|
+
#
|
|
164
|
+
# example:
|
|
165
|
+
#
|
|
166
|
+
# | jit: {"user"=>{"name"=>"Frank"}}
|
|
167
|
+
# |-- block: {"clock"=>{"timezone"=>"PST"}}
|
|
168
|
+
# |---- default_context: {"prefab-api-key"=>{"user-id"=>123}}
|
|
169
|
+
# |------ global_context: {"cpu"=>{"count"=>4, "speed"=>"2.4GHz"}, "clock"=>{"timezone"=>"UTC"}}
|
|
170
|
+
def tree(depth = 0)
|
|
171
|
+
"|" + ("-" * depth) + " #{id}: #{(" " * (30 - id.to_s.length - depth ))}#{to_h}\n" + (@parent&.tree(depth + 2) || '')
|
|
172
|
+
end
|
|
173
|
+
|
|
125
174
|
def clear
|
|
126
175
|
@contexts = {}
|
|
127
176
|
end
|
|
@@ -175,5 +224,9 @@ module Prefab
|
|
|
175
224
|
super
|
|
176
225
|
end
|
|
177
226
|
end
|
|
227
|
+
|
|
228
|
+
def id
|
|
229
|
+
@id
|
|
230
|
+
end
|
|
178
231
|
end
|
|
179
232
|
end
|
data/lib/prefab/evaluation.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Prefab
|
|
4
4
|
# Records the result of evaluating a config's criteria and forensics for reporting
|
|
5
5
|
class Evaluation
|
|
6
|
-
attr_reader :value
|
|
6
|
+
attr_reader :value, :context
|
|
7
7
|
|
|
8
8
|
def initialize(config:, value:, value_index:, config_row_index:, context:, resolver:)
|
|
9
9
|
@config = config
|
|
@@ -32,6 +32,7 @@ module Prefab
|
|
|
32
32
|
|
|
33
33
|
def report(evaluation_summary_aggregator)
|
|
34
34
|
return if @config.config_type == :LOG_LEVEL
|
|
35
|
+
|
|
35
36
|
evaluation_summary_aggregator&.record(
|
|
36
37
|
config_key: @config.key,
|
|
37
38
|
config_type: @config.config_type,
|
data/lib/prefab/options.rb
CHANGED
|
@@ -15,7 +15,7 @@ module Prefab
|
|
|
15
15
|
attr_reader :collect_sync_interval
|
|
16
16
|
attr_reader :use_local_cache
|
|
17
17
|
attr_reader :datafile
|
|
18
|
-
attr_reader :
|
|
18
|
+
attr_reader :global_context
|
|
19
19
|
attr_accessor :is_fork
|
|
20
20
|
|
|
21
21
|
module ON_INITIALIZATION_FAILURE
|
|
@@ -59,7 +59,7 @@ module Prefab
|
|
|
59
59
|
allow_telemetry_in_local_mode: false,
|
|
60
60
|
x_datafile: ENV['PREFAB_DATAFILE'],
|
|
61
61
|
x_use_local_cache: false,
|
|
62
|
-
|
|
62
|
+
global_context: {}
|
|
63
63
|
)
|
|
64
64
|
@api_key = api_key
|
|
65
65
|
@namespace = namespace
|
|
@@ -79,8 +79,8 @@ module Prefab
|
|
|
79
79
|
@collect_max_evaluation_summaries = collect_max_evaluation_summaries
|
|
80
80
|
@allow_telemetry_in_local_mode = allow_telemetry_in_local_mode
|
|
81
81
|
@use_local_cache = x_use_local_cache
|
|
82
|
-
@disable_action_controller_logging = disable_action_controller_logging
|
|
83
82
|
@is_fork = false
|
|
83
|
+
@global_context = global_context
|
|
84
84
|
|
|
85
85
|
# defaults that may be overridden by context_upload_mode
|
|
86
86
|
@collect_shapes = false
|
data/lib/prefab-cloud-ruby.rb
CHANGED
|
@@ -45,7 +45,6 @@ require 'prefab/context'
|
|
|
45
45
|
require 'prefab/logger_client'
|
|
46
46
|
require 'active_support/deprecation'
|
|
47
47
|
require 'active_support'
|
|
48
|
-
require 'action_controller/metal/strong_parameters'
|
|
49
48
|
require 'prefab/client'
|
|
50
49
|
require 'prefab/config_client_presenter'
|
|
51
50
|
require 'prefab/config_client'
|
data/prefab-cloud-ruby.gemspec
CHANGED
|
@@ -2,19 +2,18 @@
|
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
3
|
# Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
|
|
4
4
|
# -*- encoding: utf-8 -*-
|
|
5
|
-
# stub: prefab-cloud-ruby 1.6.
|
|
5
|
+
# stub: prefab-cloud-ruby 1.6.1 ruby lib
|
|
6
6
|
|
|
7
7
|
Gem::Specification.new do |s|
|
|
8
8
|
s.name = "prefab-cloud-ruby".freeze
|
|
9
|
-
s.version = "1.6.
|
|
9
|
+
s.version = "1.6.1"
|
|
10
10
|
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
|
12
12
|
s.require_paths = ["lib".freeze]
|
|
13
13
|
s.authors = ["Jeff Dwyer".freeze]
|
|
14
|
-
s.date = "2024-03-
|
|
14
|
+
s.date = "2024-03-28"
|
|
15
15
|
s.description = "Feature Flags, Live Config, and Dynamic Log Levels as a service".freeze
|
|
16
16
|
s.email = "jdwyer@prefab.cloud".freeze
|
|
17
|
-
s.executables = ["console".freeze]
|
|
18
17
|
s.extra_rdoc_files = [
|
|
19
18
|
"CHANGELOG.md",
|
|
20
19
|
"LICENSE.txt",
|
|
@@ -34,8 +33,10 @@ Gem::Specification.new do |s|
|
|
|
34
33
|
"README.md",
|
|
35
34
|
"Rakefile",
|
|
36
35
|
"VERSION",
|
|
37
|
-
"bin/console",
|
|
38
36
|
"compile_protos.sh",
|
|
37
|
+
"dev/allocation_stats",
|
|
38
|
+
"dev/benchmark",
|
|
39
|
+
"dev/console",
|
|
39
40
|
"lib/prefab-cloud-ruby.rb",
|
|
40
41
|
"lib/prefab/client.rb",
|
|
41
42
|
"lib/prefab/config_client.rb",
|
|
@@ -129,7 +130,6 @@ Gem::Specification.new do |s|
|
|
|
129
130
|
s.add_runtime_dependency(%q<ld-eventsource>.freeze, [">= 0"])
|
|
130
131
|
s.add_runtime_dependency(%q<uuid>.freeze, [">= 0"])
|
|
131
132
|
s.add_runtime_dependency(%q<activesupport>.freeze, [">= 4"])
|
|
132
|
-
s.add_runtime_dependency(%q<actionpack>.freeze, [">= 4"])
|
|
133
133
|
s.add_runtime_dependency(%q<semantic_logger>.freeze, [">= 0"])
|
|
134
134
|
s.add_development_dependency(%q<benchmark-ips>.freeze, [">= 0"])
|
|
135
135
|
s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
|
|
@@ -144,7 +144,6 @@ Gem::Specification.new do |s|
|
|
|
144
144
|
s.add_dependency(%q<ld-eventsource>.freeze, [">= 0"])
|
|
145
145
|
s.add_dependency(%q<uuid>.freeze, [">= 0"])
|
|
146
146
|
s.add_dependency(%q<activesupport>.freeze, [">= 4"])
|
|
147
|
-
s.add_dependency(%q<actionpack>.freeze, [">= 4"])
|
|
148
147
|
s.add_dependency(%q<semantic_logger>.freeze, [">= 0"])
|
|
149
148
|
s.add_dependency(%q<benchmark-ips>.freeze, [">= 0"])
|
|
150
149
|
s.add_dependency(%q<bundler>.freeze, [">= 0"])
|
|
@@ -408,6 +408,47 @@ class TestConfigResolver < Minitest::Test
|
|
|
408
408
|
end
|
|
409
409
|
end
|
|
410
410
|
|
|
411
|
+
def test_context_lookup
|
|
412
|
+
global_context = { cpu: { count: 4, speed: '2.4GHz' }, clock: { timezone: 'UTC' } }
|
|
413
|
+
default_context = { 'prefab-api-key' => { 'user-id' => 123 } }
|
|
414
|
+
local_context = { clock: { timezone: 'PST' }, user: { name: 'Ted', email: 'ted@example.com' } }
|
|
415
|
+
jit_context = { user: { name: 'Frank' } }
|
|
416
|
+
|
|
417
|
+
config = PrefabProto::Config.new( key: 'example', rows: [ PrefabProto::ConfigRow.new( values: [ PrefabProto::ConditionalValue.new( value: PrefabProto::ConfigValue.new(string: 'valueB2')) ]) ])
|
|
418
|
+
|
|
419
|
+
client = new_client(global_context: global_context, config: [config])
|
|
420
|
+
|
|
421
|
+
# we fake getting the default context from the API
|
|
422
|
+
Prefab::Context.default_context = default_context
|
|
423
|
+
|
|
424
|
+
resolver = client.resolver
|
|
425
|
+
|
|
426
|
+
client.with_context(local_context) do
|
|
427
|
+
context = resolver.get("example", jit_context).context
|
|
428
|
+
|
|
429
|
+
# This digs all the way to the global context
|
|
430
|
+
assert_equal 4, context.get('cpu.count')
|
|
431
|
+
assert_equal '2.4GHz', context.get('cpu.speed')
|
|
432
|
+
|
|
433
|
+
# This digs to the default context
|
|
434
|
+
assert_equal 123, context.get('prefab-api-key.user-id')
|
|
435
|
+
|
|
436
|
+
# This digs to the local context
|
|
437
|
+
assert_equal 'PST', context.get('clock.timezone')
|
|
438
|
+
|
|
439
|
+
# This uses the jit context
|
|
440
|
+
assert_equal 'Frank', context.get('user.name')
|
|
441
|
+
|
|
442
|
+
# This is nil in the jit context because `user` was clobbered
|
|
443
|
+
assert_nil context.get('user.email')
|
|
444
|
+
|
|
445
|
+
context = resolver.get("example").context
|
|
446
|
+
|
|
447
|
+
# But without the JIT clobbering, it is still set
|
|
448
|
+
assert_equal 'ted@example.com', context.get('user.email')
|
|
449
|
+
end
|
|
450
|
+
end
|
|
451
|
+
|
|
411
452
|
private
|
|
412
453
|
|
|
413
454
|
def resolver_for_namespace(namespace, loader, project_env_id: TEST_ENV_ID)
|
data/test/test_context.rb
CHANGED
|
@@ -15,33 +15,17 @@ class TestContext < Minitest::Test
|
|
|
15
15
|
assert_empty context.contexts
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def test_initialize_with_named_context
|
|
19
|
-
named_context = Prefab::Context::NamedContext.new('test', foo: 'bar')
|
|
20
|
-
context = Prefab::Context.new(named_context)
|
|
21
|
-
assert_equal 1, context.contexts.size
|
|
22
|
-
assert_equal named_context, context.contexts['test']
|
|
23
|
-
end
|
|
24
|
-
|
|
25
18
|
def test_initialize_with_hash
|
|
26
19
|
context = Prefab::Context.new(test: { foo: 'bar' })
|
|
27
20
|
assert_equal 1, context.contexts.size
|
|
28
|
-
assert_equal 'bar', context.
|
|
21
|
+
assert_equal 'bar', context.get("test.foo")
|
|
29
22
|
end
|
|
30
23
|
|
|
31
24
|
def test_initialize_with_multiple_hashes
|
|
32
25
|
context = Prefab::Context.new(test: { foo: 'bar' }, other: { foo: 'baz' })
|
|
33
26
|
assert_equal 2, context.contexts.size
|
|
34
|
-
assert_equal 'bar', context.
|
|
35
|
-
assert_equal 'baz', context.
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def test_initialize_with_invalid_hash
|
|
39
|
-
_, err = capture_io do
|
|
40
|
-
Prefab::Context.new({ foo: 'bar', baz: 'qux' })
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
assert_match '[DEPRECATION] Prefab contexts should be a hash with a key of the context name and a value of a hash',
|
|
44
|
-
err
|
|
27
|
+
assert_equal 'bar', context.get("test.foo")
|
|
28
|
+
assert_equal 'baz', context.get("other.foo")
|
|
45
29
|
end
|
|
46
30
|
|
|
47
31
|
def test_initialize_with_invalid_argument
|
|
@@ -56,33 +40,11 @@ class TestContext < Minitest::Test
|
|
|
56
40
|
|
|
57
41
|
def test_current_set
|
|
58
42
|
context = Prefab::Context.new(EXAMPLE_PROPERTIES)
|
|
59
|
-
Prefab::Context.current = context
|
|
43
|
+
Prefab::Context.current = context.to_h
|
|
60
44
|
assert_instance_of Prefab::Context, context
|
|
61
45
|
assert_equal stringify(EXAMPLE_PROPERTIES), context.to_h
|
|
62
46
|
end
|
|
63
47
|
|
|
64
|
-
def test_merge_with_current
|
|
65
|
-
context = Prefab::Context.new(EXAMPLE_PROPERTIES)
|
|
66
|
-
Prefab::Context.current = context
|
|
67
|
-
assert_equal stringify(EXAMPLE_PROPERTIES), context.to_h
|
|
68
|
-
|
|
69
|
-
new_context = Prefab::Context.merge_with_current({ user: { key: 'brand-new', other: 'different' },
|
|
70
|
-
address: { city: 'New York' } })
|
|
71
|
-
assert_equal stringify({
|
|
72
|
-
# Note that the user's `name` from the original
|
|
73
|
-
# context is not included. This is because we don't _merge_ the new
|
|
74
|
-
# properties if they collide with an existing context name. We _replace_
|
|
75
|
-
# them.
|
|
76
|
-
user: { key: 'brand-new', other: 'different' },
|
|
77
|
-
team: EXAMPLE_PROPERTIES[:team],
|
|
78
|
-
address: { city: 'New York' }
|
|
79
|
-
}),
|
|
80
|
-
new_context.to_h
|
|
81
|
-
|
|
82
|
-
# the original/current context is unchanged
|
|
83
|
-
assert_equal stringify(EXAMPLE_PROPERTIES), Prefab::Context.current.to_h
|
|
84
|
-
end
|
|
85
|
-
|
|
86
48
|
def test_with_context
|
|
87
49
|
Prefab::Context.with_context(EXAMPLE_PROPERTIES) do
|
|
88
50
|
context = Prefab::Context.current
|
|
@@ -105,9 +67,14 @@ class TestContext < Minitest::Test
|
|
|
105
67
|
|
|
106
68
|
def test_with_context_merge_nesting
|
|
107
69
|
Prefab::Context.with_context(EXAMPLE_PROPERTIES) do
|
|
108
|
-
Prefab::Context.with_merged_context({ user: { key: '
|
|
70
|
+
Prefab::Context.with_merged_context({ user: { key: 'hij', other: 'different' } }) do
|
|
109
71
|
context = Prefab::Context.current
|
|
110
|
-
|
|
72
|
+
assert_nil context.get('user.name')
|
|
73
|
+
assert_equal context.get('user.key'), 'hij'
|
|
74
|
+
assert_equal context.get('user.other'), 'different'
|
|
75
|
+
|
|
76
|
+
assert_equal context.get('team.key'), 'abc'
|
|
77
|
+
assert_equal context.get('team.plan'), 'pro'
|
|
111
78
|
end
|
|
112
79
|
|
|
113
80
|
context = Prefab::Context.current
|
|
@@ -187,6 +154,35 @@ class TestContext < Minitest::Test
|
|
|
187
154
|
), contexts.to_proto(namespace)
|
|
188
155
|
end
|
|
189
156
|
|
|
157
|
+
def test_parent_lookup
|
|
158
|
+
global_context = { cpu: { count: 4, speed: '2.4GHz' }, clock: { timezone: 'UTC' } }
|
|
159
|
+
default_context = { 'prefab-api-key' => { 'user-id' => 123 } }
|
|
160
|
+
local_context = { clock: { timezone: 'PST' }, user: { name: 'Ted', email: 'ted@example.com' } }
|
|
161
|
+
jit_context = { user: { name: 'Frank' } }
|
|
162
|
+
|
|
163
|
+
Prefab::Context.global_context = global_context
|
|
164
|
+
Prefab::Context.default_context = default_context
|
|
165
|
+
Prefab::Context.current = local_context
|
|
166
|
+
|
|
167
|
+
context = Prefab::Context.join(parent: Prefab::Context.current, hash: jit_context, id: :jit)
|
|
168
|
+
|
|
169
|
+
# This digs all the way to the global context
|
|
170
|
+
assert_equal 4, context.get('cpu.count')
|
|
171
|
+
assert_equal '2.4GHz', context.get('cpu.speed')
|
|
172
|
+
|
|
173
|
+
# This digs to the default context
|
|
174
|
+
assert_equal 123, context.get('prefab-api-key.user-id')
|
|
175
|
+
|
|
176
|
+
# This digs to the local context
|
|
177
|
+
assert_equal 'PST', context.get('clock.timezone')
|
|
178
|
+
|
|
179
|
+
# This uses the jit context
|
|
180
|
+
assert_equal 'Frank', context.get('user.name')
|
|
181
|
+
|
|
182
|
+
# This is nil in the jit context because `user` was clobbered
|
|
183
|
+
assert_nil context.get('user.email')
|
|
184
|
+
end
|
|
185
|
+
|
|
190
186
|
private
|
|
191
187
|
|
|
192
188
|
def stringify(hash)
|
|
@@ -10,10 +10,7 @@ class TestExampleContextsAggregator < Minitest::Test
|
|
|
10
10
|
aggregator = Prefab::ExampleContextsAggregator.new(client: MockBaseClient.new, max_contexts: 2,
|
|
11
11
|
sync_interval: EFFECTIVELY_NEVER)
|
|
12
12
|
|
|
13
|
-
context = Prefab::Context.new(
|
|
14
|
-
user: { key: 'abc' },
|
|
15
|
-
device: { key: 'def', mobile: true }
|
|
16
|
-
)
|
|
13
|
+
context = Prefab::Context.new(user: { key: 'abc' }, device: { key: 'def', mobile: true })
|
|
17
14
|
|
|
18
15
|
aggregator.record(context)
|
|
19
16
|
assert_equal [context], aggregator.data
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: prefab-cloud-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.6.
|
|
4
|
+
version: 1.6.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeff Dwyer
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-03-
|
|
11
|
+
date: 2024-03-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: concurrent-ruby
|
|
@@ -114,20 +114,6 @@ dependencies:
|
|
|
114
114
|
- - ">="
|
|
115
115
|
- !ruby/object:Gem::Version
|
|
116
116
|
version: '4'
|
|
117
|
-
- !ruby/object:Gem::Dependency
|
|
118
|
-
name: actionpack
|
|
119
|
-
requirement: !ruby/object:Gem::Requirement
|
|
120
|
-
requirements:
|
|
121
|
-
- - ">="
|
|
122
|
-
- !ruby/object:Gem::Version
|
|
123
|
-
version: '4'
|
|
124
|
-
type: :runtime
|
|
125
|
-
prerelease: false
|
|
126
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
127
|
-
requirements:
|
|
128
|
-
- - ">="
|
|
129
|
-
- !ruby/object:Gem::Version
|
|
130
|
-
version: '4'
|
|
131
117
|
- !ruby/object:Gem::Dependency
|
|
132
118
|
name: semantic_logger
|
|
133
119
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -214,8 +200,7 @@ dependencies:
|
|
|
214
200
|
version: '0'
|
|
215
201
|
description: Feature Flags, Live Config, and Dynamic Log Levels as a service
|
|
216
202
|
email: jdwyer@prefab.cloud
|
|
217
|
-
executables:
|
|
218
|
-
- console
|
|
203
|
+
executables: []
|
|
219
204
|
extensions: []
|
|
220
205
|
extra_rdoc_files:
|
|
221
206
|
- CHANGELOG.md
|
|
@@ -235,8 +220,10 @@ files:
|
|
|
235
220
|
- README.md
|
|
236
221
|
- Rakefile
|
|
237
222
|
- VERSION
|
|
238
|
-
- bin/console
|
|
239
223
|
- compile_protos.sh
|
|
224
|
+
- dev/allocation_stats
|
|
225
|
+
- dev/benchmark
|
|
226
|
+
- dev/console
|
|
240
227
|
- lib/prefab-cloud-ruby.rb
|
|
241
228
|
- lib/prefab/client.rb
|
|
242
229
|
- lib/prefab/config_client.rb
|
/data/{bin → dev}/console
RENAMED
|
File without changes
|