singleton-client 0.7.3 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
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