singleton-client 0.7.3 → 0.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +27 -28
  3. data/lib/sgtn-client/api/source.rb +10 -66
  4. data/lib/sgtn-client/api/t.rb +20 -18
  5. data/lib/sgtn-client/api/translation.rb +84 -115
  6. data/lib/sgtn-client/cldr/core_ext.rb +4 -1
  7. data/lib/sgtn-client/cldr/localized_date.rb +4 -1
  8. data/lib/sgtn-client/cldr/localized_datetime.rb +4 -1
  9. data/lib/sgtn-client/cldr/localized_str.rb +4 -1
  10. data/lib/sgtn-client/cldr/localized_time.rb +4 -1
  11. data/lib/sgtn-client/common/data.rb +30 -0
  12. data/lib/sgtn-client/common/single_operation.rb +34 -0
  13. data/lib/sgtn-client/core/cache.rb +15 -82
  14. data/lib/sgtn-client/core/config.rb +42 -3
  15. data/lib/sgtn-client/core/exceptions.rb +3 -0
  16. data/lib/sgtn-client/core/logging.rb +3 -1
  17. data/lib/sgtn-client/exceptions.rb +6 -0
  18. data/lib/sgtn-client/formatters/plurals/plural_formatter.rb +4 -1
  19. data/lib/sgtn-client/loader/cache.rb +71 -0
  20. data/lib/sgtn-client/loader/chain_loader.rb +49 -0
  21. data/lib/sgtn-client/loader/consts.rb +15 -0
  22. data/lib/sgtn-client/loader/loader_factory.rb +33 -0
  23. data/lib/sgtn-client/loader/local_translation.rb +49 -0
  24. data/lib/sgtn-client/loader/server.rb +94 -0
  25. data/lib/sgtn-client/loader/single_loader.rb +48 -0
  26. data/lib/sgtn-client/loader/source.rb +56 -0
  27. data/lib/sgtn-client/loader/source_comparer.rb +58 -0
  28. data/lib/sgtn-client/sgtn-client.rb +11 -2
  29. data/lib/sgtn-client/util/cache-util.rb +33 -41
  30. data/lib/sgtn-client/util/locale-util.rb +67 -28
  31. data/lib/sgtn-client/util/string-util.rb +12 -0
  32. data/lib/sgtn-client/util/validate-util.rb +5 -9
  33. data/lib/singleton-client.rb +15 -0
  34. data/lib/singleton-ruby.rb +5 -0
  35. data/lib/version.rb +2 -0
  36. metadata +43 -147
  37. data/lib/sgtn-client/core/request.rb +0 -21
  38. data/lib/sgtn-client/util/file-util.rb +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3fa11214d62c5669477f86cf9cdd5535112c9fa48ec46504e192048e008173cc
4
- data.tar.gz: 29675027bf9d235c59728680dd791a11665209c4e99445032410c38166db6463
3
+ metadata.gz: a587958936d82290e3937f0a96097f4254bb3e8743673a808702a2881d414ff9
4
+ data.tar.gz: f60706e62d08f058fca8eb1b286800f61f4a79f78cd5aadb4b1c53ed7736f62f
5
5
  SHA512:
6
- metadata.gz: f62c62c7e7d0e49124e8cdbd648154099e8d3b6bf5a8ac295b25817acefaf71a89dd09d6a8e1ef4f766f9e42d2ffb398af5e92f832933e650fef556aab767d53
7
- data.tar.gz: 0d97b5eb531a64e9be1543edf3bebcc78ebc094fa06db9f711a1bb1e365ec42c4cfc0a96ffa5130f220a1c39f38ab57f10fb3120fea266ad698607557069143a
6
+ metadata.gz: 7f89add299ebf85604d748fdc5c3d4e0fed05f98810514ca4de8b23eb3305af0568c32d308b59fa2b54f1f3188531de4c07732d6d5c59d4d13cc3a6f6ef0cb21
7
+ data.tar.gz: c2192d0d69ed16250d55a5f9e255c4ede49b404cc93f90ae3d266aa1663cdfcdce114317b593509a8be64e0f6d3587811eb4f8587b39517c08a5647460a462d1
data/README.md CHANGED
@@ -1,54 +1,53 @@
1
- # Singeleton client for Ruby
1
+ # Singleton Client for Ruby
2
2
 
3
3
  ## Prerequisites
4
4
  - Ruby version: 3.0.0 or above
5
5
  - Bundler version: 2.2.3 or above
6
6
 
7
7
  ## Run Unit Test
8
- rake spec:unit
8
+ `rake spec`
9
9
 
10
10
  ## Usage
11
11
 
12
12
  Basic Usage:
13
13
 
14
14
  ```ruby
15
- require 'singleton-ruby'
16
-
17
- include SgtnClient
18
-
19
- SgtnClient.load(file, mode)
20
-
21
- SgtnClient::Source.loadBundles(locale)
22
-
23
- @Result = SgtnClient::Translation.getString(component, key, locale)
15
+ require 'singleton-client'
24
16
 
17
+ Sgtn.load_config(file, env)
18
+ result = Sgtn.translate(key, component, locale)
25
19
  ```
26
20
  ## API Usage
27
21
 
28
22
  ### Get a string's translation
29
- SgtnClient::Translation.getString(component, key, locale)
30
-
31
- ### Get a string's translation and format it with placeholders
32
- SgtnClient::Translation.getString_f(component, key, args, locale)
33
-
34
- ### Get a component's translations
35
- SgtnClient::Translation.getStrings(component, locale)
36
-
23
+ `result = Sgtn.translate(key, component, locale)`
37
24
 
38
- ## API Usage(with request_store)
39
-
40
- Before call below APIs(without locale and component arguments), it requires to set the locale and component in the initial codes.
41
-
42
- ### Get a string's translation
43
- SgtnClient::T.s(key)
25
+ ### Get a string's translation with default value when no translation
26
+ `result = Sgtn.translate(key, component, locale) { 'default value' }`
44
27
 
45
28
  ### Get a string's translation and format it with placeholders
46
- SgtnClient::T.s_f(key, args)
29
+ `result = Sgtn.translate(key, component, locale, **args)`
47
30
 
48
- ### Get a component's translations
49
- SgtnClient::T.c()
31
+ ### Get pluralized translation
32
+ `result = Sgtn.translate(key, component, locale, **args)`
50
33
 
34
+ ### Get translations of a bundle
35
+ `result = Sgtn.get_translations(component, locale)`
51
36
 
37
+ ### Set locale for a request
38
+ `Sgtn.locale = 'en'`
52
39
 
40
+ ### Get locale of the request
41
+ `result = Sgtn.locale`
53
42
 
43
+ ### Get a string's translation with locale set
44
+ ```ruby
45
+ Sgtn.locale = 'en'
46
+ result = Sgtn.translate(key, component)
47
+ ```
54
48
 
49
+ ### Get translations of a bundle with locale set
50
+ ```ruby
51
+ Sgtn.locale = 'en'
52
+ result = Sgtn.get_translations(component)
53
+ ```
@@ -1,71 +1,15 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
4
+ require 'sgtn-client/loader/source'
1
5
 
2
6
  module SgtnClient
3
-
4
- autoload :CacheUtil, "sgtn-client/util/cache-util"
7
+ autoload :CacheUtil, 'sgtn-client/util/cache-util'
5
8
 
6
9
  class Source
7
-
8
- def self.getSource(component, key, locale)
9
- cache_key = SgtnClient::CacheUtil.get_cachekey(component, locale)
10
- expired, items = SgtnClient::CacheUtil.get_cache(cache_key)
11
- if items.nil?
12
- items = getBundle(component, locale)
13
- SgtnClient.logger.debug "Putting sources items into cache with key: " + cache_key
14
- SgtnClient::CacheUtil.write_cache(cache_key, items)
15
- else
16
- SgtnClient.logger.debug "Getting sources from cache with key: " + cache_key
17
- end
18
- s = items.nil?? nil : items[locale][key]
19
- if items.nil? || s.nil?
20
- SgtnClient.logger.debug "Source not found, return key: " + key
21
- #return key
22
- return nil
23
- else
24
- return s
25
- end
26
- end
27
-
28
- def self.getSources(component, locale)
29
- cache_key = SgtnClient::CacheUtil.get_cachekey(component, locale)
30
- expired, items = SgtnClient::CacheUtil.get_cache(cache_key)
31
- if items.nil? || expired
32
- items = getBundle(component, locale)
33
- SgtnClient.logger.debug "Putting sources items into cache with key: " + cache_key
34
- SgtnClient::CacheUtil.write_cache(cache_key, items)
35
- else
36
- SgtnClient.logger.debug "Getting sources from cache with key: " + cache_key
37
- end
38
- return items
39
- end
40
-
41
- def self.loadBundles(locale)
42
- env = SgtnClient::Config.default_environment
43
- SgtnClient::Config.configurations.default = locale
44
- source_bundle = SgtnClient::Config.configurations[env]["source_bundle"]
45
- SgtnClient.logger.debug "Loading [" + locale + "] source bundles from path: " + source_bundle
46
- Dir.foreach(source_bundle) do |component|
47
- next if component == '.' || component == '..'
48
- yamlfile = File.join(source_bundle, component + "/" + locale + ".yml")
49
- bundle = SgtnClient::FileUtil.read_yml(yamlfile)
50
- cachekey = SgtnClient::CacheUtil.get_cachekey(component, locale)
51
- SgtnClient::CacheUtil.write_cache(cachekey,bundle)
52
- end
53
- end
54
-
55
- private
56
- def self.getBundle(component, locale)
57
- env = SgtnClient::Config.default_environment
58
- source_bundle = SgtnClient::Config.configurations[env]["source_bundle"]
59
- bundlepath = source_bundle + "/" + component + "/" + locale + ".yml"
60
- SgtnClient.logger.debug "Getting source from bundle: " + bundlepath
61
- begin
62
- bundle = SgtnClient::FileUtil.read_yml(bundlepath)
63
- rescue => exception
64
- SgtnClient.logger.error exception.message
65
- end
66
- return bundle
67
- end
68
-
10
+ def self.loadBundles(locale)
11
+ SgtnClient.logger.debug "[Source][loadBundles]locale=#{locale}"
12
+ SgtnClient::Config.configurations.default = locale
13
+ end
69
14
  end
70
-
71
- end
15
+ end
@@ -1,22 +1,24 @@
1
- module SgtnClient
2
- class T < Translation
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
3
 
4
- def self.s(key)
5
- locale = RequestStore.store[:locale]
6
- component = RequestStore.store[:component]
7
- return getString(component, key, locale)
8
- end
4
+ module SgtnClient
5
+ class T
6
+ def self.s(key)
7
+ locale = RequestStore.store[:locale]
8
+ component = RequestStore.store[:component]
9
+ Translation.getString(component, key, locale)
10
+ end
9
11
 
10
- def self.s_f(key, args)
11
- locale = RequestStore.store[:locale]
12
- component = RequestStore.store[:component]
13
- return getString_f(component, key, args, locale)
14
- end
12
+ def self.s_f(key, args)
13
+ locale = RequestStore.store[:locale]
14
+ component = RequestStore.store[:component]
15
+ Translation.getString_f(component, key, args, locale)
16
+ end
15
17
 
16
- def self.c()
17
- locale = RequestStore.store[:locale]
18
- component = RequestStore.store[:component]
19
- return getStrings(component, locale)
20
- end
18
+ def self.c
19
+ locale = RequestStore.store[:locale]
20
+ component = RequestStore.store[:component]
21
+ Translation.getStrings(component, locale)
21
22
  end
22
- end
23
+ end
24
+ end
@@ -1,144 +1,113 @@
1
- require 'multi_json'
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
2
3
 
3
- module SgtnClient
4
+ require 'request_store'
4
5
 
5
- module Core
6
- autoload :Request, "sgtn-client/core/request"
7
- autoload :Cache, "sgtn-client/core/cache"
8
- autoload :CacheUtil, "sgtn-client/util/cache-util"
9
- autoload :LocaleUtil, "sgtn-client/util/locale-util"
10
- end
11
-
12
- class Translation
13
-
14
- def self.getString(component, key, locale)
15
- str = getTranslation(component, key, locale)
16
- if str.nil?
17
- str = SgtnClient::Source.getSource(component, key, SgtnClient::Config.configurations.default)
18
- if str.nil?
19
- SgtnClient.logger.error "Can't find the key '" + key + "' in source path!"
20
- end
21
- end
22
- str
6
+ module SgtnClient
7
+ module Translation
8
+ module Implementation
9
+ # <b>DEPRECATED:</b> Please use <tt>Sgtn:translate</tt> instead.
10
+ def getString(component, key, locale)
11
+ SgtnClient.logger.debug "[Translation.getString]component: #{component}, key: #{key}, locale: #{locale}"
12
+ translate(key, component, locale) { nil }
23
13
  end
24
14
 
25
- def self.getString_p(component, key, plural_args, locale)
26
- str = getTranslation(component, key, locale)
27
- if str.nil?
28
- str = SgtnClient::Source.getSource(component, key, SgtnClient::Config.configurations.default)
29
- if str.nil?
30
- SgtnClient.logger.error "Can't find the key '" + key + "' in source path!"
31
- return nil
32
- end
33
- str.to_plural_s(:en, plural_args)
34
- else
35
- str.to_plural_s(locale, plural_args)
36
- end
15
+ # <b>DEPRECATED:</b> Please use <tt>Sgtn:translate</tt> instead.
16
+ def getString_p(component, key, plural_args, locale)
17
+ SgtnClient.logger.debug "[Translation][getString_p]component=#{component}, key=#{key}, locale=#{locale}"
18
+ translate(key, component, locale, **plural_args) { nil }
37
19
  end
38
20
 
39
- def self.getString_f(component, key, args, locale, *optionals)
40
- s = getString(component, key, locale, *optionals)
41
- if s.nil?
42
- return nil
43
- end
44
- if args.is_a?(Hash)
21
+ # <b>DEPRECATED:</b> Please use <tt>Sgtn:translate</tt> instead.
22
+ def getString_f(component, key, args, locale, *_optionals)
23
+ SgtnClient.logger.debug "[Translation][getString_f]component=#{component}, key=#{key}, locale=#{locale}"
24
+ s = translate(key, component, locale) { nil }
25
+ return nil if s.nil?
26
+
27
+ if args.is_a?(Hash)
45
28
  args.each do |source, arg|
46
29
  s.gsub! "{#{source}}", arg
47
30
  end
48
- elsif args.is_a?(Array)
49
- s = sprintf s % args
50
- end
51
- return s
31
+ elsif args.is_a?(Array)
32
+ s = s % args
33
+ end
34
+ s
52
35
  end
53
36
 
54
- def self.getStrings(component, locale)
55
- items = get_cs(component, locale)
56
- default = SgtnClient::Config.configurations.default
57
- if items.nil? || items["messages"] == nil
58
- items = {}
59
- s = SgtnClient::Source.getSources(component, default)
60
- if s.nil?
61
- SgtnClient.logger.error "Can't find the component '" + component + "' in source path!"
62
- else
63
- default_component, value = s.first
64
- items["component"] = component
65
- items["messages"] = value
66
- items["locale"] = 'source'
67
- end
37
+ # <b>DEPRECATED:</b> Please use <tt>Sgtn:get_translations</tt> instead.
38
+ def getStrings(component, locale)
39
+ get_translations(component, locale)
40
+ end
41
+
42
+ # raise error when translation is not found
43
+ def translate(key, component, locale = nil, **kwargs)
44
+ SgtnClient.logger.debug "[#{method(__callee__).owner}.#{__callee__}] key: #{key}, component: #{component}, locale: #{locale}, args: #{kwargs}"
45
+
46
+ locale = locale.nil? ? self.locale : SgtnClient::LocaleUtil.get_best_locale(locale)
47
+
48
+ result = get_bundle(component, locale)&.fetch(key, nil)
49
+ if result.nil? && !LocaleUtil.is_source_locale(locale)
50
+ locale = LocaleUtil.get_source_locale
51
+ result = get_bundle(component, locale)&.fetch(key, nil)
68
52
  end
69
- return items
70
- end
71
53
 
54
+ if result.nil?
55
+ return key unless block_given?
72
56
 
73
- private
57
+ result = yield
58
+ return if result.nil?
59
+ end
74
60
 
75
- def self.getTranslation(component, key, locale)
76
- items = get_cs(component, locale)
77
- if items.nil? || items["messages"] == nil
78
- nil
61
+ if kwargs.empty?
62
+ result
79
63
  else
80
- items["messages"][key]
64
+ locale = result.locale if result.is_a?(SgtnClient::StringUtil)
65
+ result.localize(locale) % kwargs
81
66
  end
82
67
  end
68
+ alias t translate
83
69
 
84
- def self.get_cs(component, locale)
85
- flocale = SgtnClient::LocaleUtil.fallback(locale)
86
- cache_key = SgtnClient::CacheUtil.get_cachekey(component, flocale)
87
- expired, items = SgtnClient::CacheUtil.get_cache(cache_key)
88
- if items.nil? || expired
89
- items = load(component, flocale)
90
- if items.nil?
91
- items = SgtnClient::Source.getSources(component, SgtnClient::Config.configurations.default)
92
- SgtnClient::Core::Cache.put(cache_key, items, 60)
93
- else
94
- SgtnClient::CacheUtil.write_cache(cache_key, items)
95
- end
96
- else
97
- SgtnClient.logger.debug "Getting translations from cache with key: " + cache_key
70
+ def get_translations(component, locale = nil)
71
+ SgtnClient.logger.debug "[#{method(__callee__).owner}.#{__callee__}] component: #{component}, locale: #{locale}"
72
+
73
+ locale = locale.nil? ? self.locale : SgtnClient::LocaleUtil.get_best_locale(locale)
74
+ items = get_bundle(component, locale)
75
+ if items.nil? && !LocaleUtil.is_source_locale(locale)
76
+ items = get_bundle(component, LocaleUtil.get_source_locale)
77
+ locale = LocaleUtil.get_source_locale
98
78
  end
99
79
 
100
- return items
101
- end
80
+ { 'component' => component, 'locale' => locale, 'messages' => items || {} } if items
81
+ end
102
82
 
103
- def self.load(component, locale)
104
- env = SgtnClient::Config.default_environment
105
- mode = SgtnClient::Config.configurations[env]["bundle_mode"]
106
- if mode == 'offline'
107
- return load_o(component, locale)
108
- else
109
- return load_s(component, locale)
110
- end
83
+ def locale
84
+ RequestStore.store[:locale] ||= SgtnClient::LocaleUtil.get_fallback_locale
111
85
  end
112
86
 
113
- def self.load_o(component, locale)
114
- env = SgtnClient::Config.default_environment
115
- product_name = SgtnClient::Config.configurations[env]["product_name"]
116
- version = SgtnClient::Config.configurations[env]["version"].to_s
117
- translation_bundle = SgtnClient::Config.configurations[env]["translation_bundle"]
118
- bundlepath = translation_bundle + "/" + product_name + "/" + version + "/" + component + "/messages_" + locale + ".json"
119
- SgtnClient.logger.debug "Getting translations from offline bundle: " + bundlepath
120
- SgtnClient::FileUtil.read_json(bundlepath)
87
+ def locale=(value)
88
+ RequestStore.store[:locale] = SgtnClient::LocaleUtil.get_best_locale(value)
121
89
  end
122
90
 
123
- def self.load_s(component, locale)
124
- env = SgtnClient::Config.default_environment
125
- product_name = SgtnClient::Config.configurations[env]["product_name"]
126
- vip_server = SgtnClient::Config.configurations[env]["vip_server"]
127
- SgtnClient.logger.debug "Getting translations from server: " + vip_server
128
- version = SgtnClient::Config.configurations[env]["version"].to_s
129
- url = vip_server + "/i18n/api/v2/translation/products/" + product_name + "/versions/" + version + "/locales/" + locale + "/components/" + component+ "?checkTranslationStatus=false&machineTranslation=false&pseudo=false"
130
- SgtnClient.logger.debug url
131
- begin
132
- obj = SgtnClient::Core::Request.get(url)
133
- rescue => exception
134
- SgtnClient.logger.error exception.message
135
- end
136
- if obj != nil
137
- obj = obj["data"]
138
- end
139
- return obj
91
+ private
92
+
93
+ def get_bundle(component, locale)
94
+ get_bundle!(component, locale)
95
+ rescue StandardError => e
96
+ SgtnClient.logger.error "[#{method(__callee__).owner}.#{__callee__}] failed to get a bundle. component: #{component}, locale: #{locale}"
97
+ SgtnClient.logger.error e
98
+ nil
140
99
  end
141
100
 
142
- end
101
+ def get_bundle!(component, locale)
102
+ id = SgtnClient::Common::BundleID.new(component, locale)
103
+ bundles = SgtnClient::Config.available_bundles
104
+ unless bundles.nil? || bundles.empty? || bundles.include?(id)
105
+ raise SgtnClient::SingletonError, 'bundle is unavailable.'
106
+ end
143
107
 
144
- end
108
+ SgtnClient::Config.loader.get_bundle(component, locale)
109
+ end
110
+ end
111
+ extend Implementation
112
+ end
113
+ end
@@ -1,4 +1,7 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
1
4
  require 'sgtn-client/cldr/localized_datetime'
2
5
  require 'sgtn-client/cldr/localized_date'
3
6
  require 'sgtn-client/cldr/localized_time'
4
- require 'sgtn-client/cldr/localized_str'
7
+ require 'sgtn-client/cldr/localized_str'
@@ -1,3 +1,6 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
1
4
  require 'date'
2
5
  require 'time'
3
6
 
@@ -24,4 +27,4 @@ Date.class_eval <<-LOCALIZE, __FILE__, __LINE__ + 1
24
27
  def l_short_s(locale = TwitterCldr.locale)
25
28
  self.to_datetime().localize(locale).to_date().to_short_s
26
29
  end
27
- LOCALIZE
30
+ LOCALIZE
@@ -1,3 +1,6 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
1
4
  require 'date'
2
5
  require 'time'
3
6
 
@@ -60,4 +63,4 @@ DateTime.class_eval <<-LOCALIZE, __FILE__, __LINE__ + 1
60
63
  tz.display_name_for(self, display_name)
61
64
  end
62
65
  end
63
- LOCALIZE
66
+ LOCALIZE
@@ -1,5 +1,8 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
1
3
 
2
4
  String.class_eval <<-LOCALIZE, __FILE__, __LINE__ + 1
5
+ # <b>DEPRECATED:</b> Please use <tt>Sgtn:translate</tt> instead.
3
6
  def to_plural_s(locale, arg)
4
7
  num_str = SgtnClient::Formatters::PluralFormatter.new(locale).num_s(self, arg)
5
8
  if num_str.nil? || num_str.empty?
@@ -8,4 +11,4 @@ String.class_eval <<-LOCALIZE, __FILE__, __LINE__ + 1
8
11
  num_str
9
12
  end
10
13
  end
11
- LOCALIZE
14
+ LOCALIZE
@@ -1,3 +1,6 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
1
4
  require 'date'
2
5
  require 'time'
3
6
 
@@ -24,4 +27,4 @@ Time.class_eval <<-LOCALIZE, __FILE__, __LINE__ + 1
24
27
  def l_short_s(locale = TwitterCldr.locale)
25
28
  self.localize(locale).to_short_s
26
29
  end
27
- LOCALIZE
30
+ LOCALIZE
@@ -0,0 +1,30 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
4
+ module SgtnClient
5
+ module Common
6
+ class BundleID
7
+ attr_reader :locale, :component
8
+
9
+ def initialize(component, locale)
10
+ @locale = locale
11
+ @component = component
12
+ @key = [@component, @locale].hash
13
+ end
14
+
15
+ def hash
16
+ @key
17
+ end
18
+
19
+ def ==(other)
20
+ (other.is_a? self.class) && @locale == other.locale && @component == other.component
21
+ end
22
+
23
+ alias eql? ==
24
+
25
+ def to_s
26
+ "locale=#{@locale}, component=#{@component}}"
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,34 @@
1
+ # Copyright 2022 VMware, Inc.
2
+ # SPDX-License-Identifier: EPL-2.0
3
+
4
+ module SgtnClient
5
+ class SingleOperation
6
+ def initialize(*conditions, &block)
7
+ raise 'no way to create a new obj' unless block
8
+
9
+ @lock = Mutex.new
10
+ @hash = {}
11
+
12
+ @conditions = conditions
13
+ @creator = block
14
+ end
15
+
16
+ # return new created object
17
+ def operate(id, *args)
18
+ @lock.synchronize do
19
+ obj = @hash[id]
20
+ @conditions.each do |con|
21
+ return obj unless con.call(id, obj, *args)
22
+ end
23
+ # TODO: whatif returning nil
24
+ @hash[id] = @creator.call(id, obj, *args)
25
+ end
26
+ end
27
+
28
+ def remove_object(id)
29
+ @lock.synchronize do
30
+ @hash.delete(id)
31
+ end
32
+ end
33
+ end
34
+ end