i18n 1.0.0 → 1.0.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: 39f37c32e4547234644c06bad5f78487e301f8aea4a2aa47c94bebb568c75a05
4
- data.tar.gz: 9b3cb30997b5bb52f1a4a9ee4504211011208be9ce8d308afb2007b291ae40d3
3
+ metadata.gz: 6abb11703c717406a1a4e5df13e88679656a3bb798cd0141e4ef9961fed64056
4
+ data.tar.gz: 1e633332f63054b3919c887a853a1bb4348025550531bf3f499a924a1b37acf5
5
5
  SHA512:
6
- metadata.gz: eb93464f794724a7fbc84526765766c2f9f815c0ae093bba9996ab7c7ad2cad266e72a13b37361278b954e3fea84e21dcee913f8f5d4da22e5dba32fade24a32
7
- data.tar.gz: a8223afdd56a948194455df49da3c23f754a492053080bb6c0b7b8e386ac068f8a9756b1cf5e620c517d5bc26e4d8a448aab7d1effd794f974e8d9d233086fca
6
+ metadata.gz: 6fe991afffcec28225b53932a1977c6c30ee6f8a79a0256380a552f25ca6d0bffd3b21452d8177529d97aac9f880e1296072804942c0b99a379ecfeb6c8ca446
7
+ data.tar.gz: b8a7625539fe9e5c0c49b0a85a3bce54c1fb46e68ed4910870aee8c6f37afb589888b3ba87a6786e4364021a831619874f796a38eea6d0e6b285f67e232b3926
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'concurrent/map'
2
4
 
3
5
  require 'i18n/version'
@@ -12,9 +14,23 @@ module I18n
12
14
  autoload :Tests, 'i18n/tests'
13
15
  autoload :Middleware, 'i18n/middleware'
14
16
 
15
- RESERVED_KEYS = [:scope, :default, :separator, :resolve, :object, :fallback, :fallback_in_progress, :format, :cascade, :throw, :raise, :deep_interpolation]
17
+ RESERVED_KEYS = %i[
18
+ cascade
19
+ deep_interpolation
20
+ default
21
+ exception_handler
22
+ fallback
23
+ fallback_in_progress
24
+ format
25
+ object
26
+ raise
27
+ resolve
28
+ scope
29
+ separator
30
+ throw
31
+ ].freeze
16
32
  RESERVED_KEYS_PATTERN = /%\{(#{RESERVED_KEYS.join("|")})\}/
17
-
33
+ EMPTY_HASH = {}.freeze
18
34
 
19
35
  def self.new_double_nested_cache # :nodoc:
20
36
  Concurrent::Map.new { |h,k| h[k] = Concurrent::Map.new }
@@ -175,7 +191,7 @@ module I18n
175
191
 
176
192
  # Wrapper for <tt>translate</tt> that adds <tt>:raise => true</tt>. With
177
193
  # this option, if no translation is found, it will raise <tt>I18n::MissingTranslationData</tt>
178
- def translate!(key, options={})
194
+ def translate!(key, options = EMPTY_HASH)
179
195
  translate(key, options.merge(:raise => true))
180
196
  end
181
197
  alias :t! :translate!
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  module Backend
3
5
  autoload :Base, 'i18n/backend/base'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
  require 'i18n/core_ext/hash'
3
5
  require 'i18n/core_ext/kernel/suppress_warnings'
@@ -17,11 +19,11 @@ module I18n
17
19
 
18
20
  # This method receives a locale, a data hash and options for storing translations.
19
21
  # Should be implemented
20
- def store_translations(locale, data, options = {})
22
+ def store_translations(locale, data, options = EMPTY_HASH)
21
23
  raise NotImplementedError
22
24
  end
23
25
 
24
- def translate(locale, key, options = {})
26
+ def translate(locale, key, options = EMPTY_HASH)
25
27
  raise I18n::ArgumentError if (key.is_a?(String) || key.is_a?(Symbol)) && key.empty?
26
28
  raise InvalidLocale.new(locale) unless locale
27
29
  return nil if key.nil? && !options.key?(:default)
@@ -68,7 +70,7 @@ module I18n
68
70
  # Acts the same as +strftime+, but uses a localized version of the
69
71
  # format string. Takes a key from the date/time formats translations as
70
72
  # a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>).
71
- def localize(locale, object, format = :default, options = {})
73
+ def localize(locale, object, format = :default, options = EMPTY_HASH)
72
74
  if object.nil? && options.include?(:default)
73
75
  return options[:default]
74
76
  end
@@ -97,7 +99,7 @@ module I18n
97
99
  protected
98
100
 
99
101
  # The method which actually looks up for the translation in the store.
100
- def lookup(locale, key, scope = [], options = {})
102
+ def lookup(locale, key, scope = [], options = EMPTY_HASH)
101
103
  raise NotImplementedError
102
104
  end
103
105
 
@@ -109,7 +111,7 @@ module I18n
109
111
  # If given subject is an Array, it walks the array and returns the
110
112
  # first translation that can be resolved. Otherwise it tries to resolve
111
113
  # the translation directly.
112
- def default(locale, object, subject, options = {})
114
+ def default(locale, object, subject, options = EMPTY_HASH)
113
115
  options = options.dup.reject { |key, value| key == :default }
114
116
  case subject
115
117
  when Array
@@ -126,7 +128,7 @@ module I18n
126
128
  # If the given subject is a Symbol, it will be translated with the
127
129
  # given options. If it is a Proc then it will be evaluated. All other
128
130
  # subjects will be returned directly.
129
- def resolve(locale, object, subject, options = {})
131
+ def resolve(locale, object, subject, options = EMPTY_HASH)
130
132
  return subject if options[:resolve] == false
131
133
  result = catch(:exception) do
132
134
  case subject
@@ -168,7 +170,7 @@ module I18n
168
170
  # each element of the array is recursively interpolated (until it finds a string)
169
171
  # method interpolates ["yes, %{user}", ["maybe no, %{user}, "no, %{user}"]], :user => "bartuz"
170
172
  # # => "["yes, bartuz",["maybe no, bartuz", "no, bartuz"]]"
171
- def interpolate(locale, subject, values = {})
173
+ def interpolate(locale, subject, values = EMPTY_HASH)
172
174
  return subject if values.empty?
173
175
 
174
176
  case subject
@@ -184,7 +186,7 @@ module I18n
184
186
  # deep_interpolate { people: { ann: "Ann is %{ann}", john: "John is %{john}" } },
185
187
  # ann: 'good', john: 'big'
186
188
  # #=> { people: { ann: "Ann is good", john: "John is big" } }
187
- def deep_interpolate(locale, data, values = {})
189
+ def deep_interpolate(locale, data, values = EMPTY_HASH)
188
190
  return data if values.empty?
189
191
 
190
192
  case data
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This module allows you to easily cache all responses from the backend - thus
2
4
  # speeding up the I18n aspects of your application quite a bit.
3
5
  #
@@ -14,9 +16,9 @@
14
16
  # ActiveSupport::Cache (only the methods #fetch and #write are being used).
15
17
  #
16
18
  # The cache_key implementation by default assumes you pass values that return
17
- # a valid key from #hash (see
18
- # http://www.ruby-doc.org/core/classes/Object.html#M000337). However, you can
19
- # configure your own digest method via which responds to #hexdigest (see
19
+ # a valid key from #hash (see
20
+ # http://www.ruby-doc.org/core/classes/Object.html#M000337). However, you can
21
+ # configure your own digest method via which responds to #hexdigest (see
20
22
  # http://ruby-doc.org/stdlib/libdoc/digest/rdoc/index.html):
21
23
  #
22
24
  # I18n.cache_key_digest = Digest::MD5.new
@@ -75,7 +77,7 @@ module I18n
75
77
  module Backend
76
78
  # TODO Should the cache be cleared if new translations are stored?
77
79
  module Cache
78
- def translate(locale, key, options = {})
80
+ def translate(locale, key, options = EMPTY_HASH)
79
81
  I18n.perform_caching? ? fetch(cache_key(locale, key, options)) { super } : super
80
82
  end
81
83
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # The Cascade module adds the ability to do cascading lookups to backends that
2
4
  # are compatible to the Simple backend.
3
5
  #
@@ -31,7 +33,7 @@
31
33
  module I18n
32
34
  module Backend
33
35
  module Cascade
34
- def lookup(locale, key, scope = [], options = {})
36
+ def lookup(locale, key, scope = [], options = EMPTY_HASH)
35
37
  return super unless cascade = options[:cascade]
36
38
 
37
39
  cascade = { :step => 1 } unless cascade.is_a?(Hash)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  module Backend
3
5
  # Backend that chains multiple other backends and checks each of them when
@@ -28,7 +30,7 @@ module I18n
28
30
  backends.each { |backend| backend.reload! }
29
31
  end
30
32
 
31
- def store_translations(locale, data, options = {})
33
+ def store_translations(locale, data, options = EMPTY_HASH)
32
34
  backends.first.store_translations(locale, data, options)
33
35
  end
34
36
 
@@ -36,7 +38,7 @@ module I18n
36
38
  backends.map { |backend| backend.available_locales }.flatten.uniq
37
39
  end
38
40
 
39
- def translate(locale, key, default_options = {})
41
+ def translate(locale, key, default_options = EMPTY_HASH)
40
42
  namespace = nil
41
43
  options = default_options.except(:default)
42
44
 
@@ -62,7 +64,7 @@ module I18n
62
64
  end
63
65
  end
64
66
 
65
- def localize(locale, object, format = :default, options = {})
67
+ def localize(locale, object, format = :default, options = EMPTY_HASH)
66
68
  backends.each do |backend|
67
69
  catch(:exception) do
68
70
  result = backend.localize(locale, object, format, options) and return result
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # I18n locale fallbacks are useful when you want your application to use
2
4
  # translations from other locales when translations for the current locale are
3
5
  # missing. E.g. you might want to use :en translations when translations in
@@ -34,25 +36,21 @@ module I18n
34
36
  # The default option takes precedence over fallback locales only when
35
37
  # it's a Symbol. When the default contains a String, Proc or Hash
36
38
  # it is evaluated last after all the fallback locales have been tried.
37
- def translate(locale, key, options = {})
39
+ def translate(locale, key, options = EMPTY_HASH)
38
40
  return super unless options.fetch(:fallback, true)
39
41
  return super if options[:fallback_in_progress]
40
42
  default = extract_non_symbol_default!(options) if options[:default]
41
43
 
42
- begin
43
- options[:fallback_in_progress] = true
44
- I18n.fallbacks[locale].each do |fallback|
45
- begin
46
- catch(:exception) do
47
- result = super(fallback, key, options)
48
- return result unless result.nil?
49
- end
50
- rescue I18n::InvalidLocale
51
- # we do nothing when the locale is invalid, as this is a fallback anyways.
44
+ fallback_options = options.merge(:fallback_in_progress => true)
45
+ I18n.fallbacks[locale].each do |fallback|
46
+ begin
47
+ catch(:exception) do
48
+ result = super(fallback, key, fallback_options)
49
+ return result unless result.nil?
52
50
  end
51
+ rescue I18n::InvalidLocale
52
+ # we do nothing when the locale is invalid, as this is a fallback anyways.
53
53
  end
54
- ensure
55
- options.delete(:fallback_in_progress)
56
54
  end
57
55
 
58
56
  return if options.key?(:default) && options[:default].nil?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  module Backend
3
5
  # This module contains several helpers to assist flattening translations.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'i18n/gettext'
2
4
  require 'i18n/gettext/po_parser'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # The InterpolationCompiler module contains optimizations that can tremendously
2
4
  # speed up the interpolation process on the Simple backend.
3
5
  #
@@ -104,7 +106,7 @@ module I18n
104
106
  end
105
107
  end
106
108
 
107
- def store_translations(locale, data, options = {})
109
+ def store_translations(locale, data, options = EMPTY_HASH)
108
110
  compile_all_strings_in(data)
109
111
  super
110
112
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'i18n/backend/base'
2
4
 
3
5
  module I18n
@@ -74,7 +76,7 @@ module I18n
74
76
  @store, @subtrees = store, subtrees
75
77
  end
76
78
 
77
- def store_translations(locale, data, options = {})
79
+ def store_translations(locale, data, options = EMPTY_HASH)
78
80
  escape = options.fetch(:escape, true)
79
81
  flatten_translations(locale, data, escape, @subtrees).each do |key, value|
80
82
  key = "#{locale}.#{key}"
@@ -107,7 +109,7 @@ module I18n
107
109
  @subtrees
108
110
  end
109
111
 
110
- def lookup(locale, key, scope = [], options = {})
112
+ def lookup(locale, key, scope = [], options = EMPTY_HASH)
111
113
  key = normalize_flat_keys(locale, key, scope, options[:separator])
112
114
  value = @store["#{locale}.#{key}"]
113
115
  value = JSON.decode(value) if value
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Memoize module simply memoizes the values returned by lookup using
2
4
  # a flat hash and can tremendously speed up the lookup process in a backend.
3
5
  #
@@ -14,7 +16,7 @@ module I18n
14
16
  @memoized_locales ||= super
15
17
  end
16
18
 
17
- def store_translations(locale, data, options = {})
19
+ def store_translations(locale, data, options = EMPTY_HASH)
18
20
  reset_memoizations!(locale)
19
21
  super
20
22
  end
@@ -26,7 +28,7 @@ module I18n
26
28
 
27
29
  protected
28
30
 
29
- def lookup(locale, key, scope = nil, options = {})
31
+ def lookup(locale, key, scope = nil, options = EMPTY_HASH)
30
32
  flat_key = I18n::Backend::Flatten.normalize_flat_keys(locale,
31
33
  key, scope, options[:separator]).to_sym
32
34
  flat_hash = memoized_lookup[locale.to_sym]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # I18n translation metadata is useful when you want to access information
2
4
  # about how a translation was looked up, pluralized or interpolated in
3
5
  # your application.
@@ -35,19 +37,19 @@ module I18n
35
37
  end
36
38
  end
37
39
 
38
- def translate(locale, key, options = {})
40
+ def translate(locale, key, options = EMPTY_HASH)
39
41
  metadata = {
40
42
  :locale => locale,
41
43
  :key => key,
42
44
  :scope => options[:scope],
43
45
  :default => options[:default],
44
46
  :separator => options[:separator],
45
- :values => options.reject { |name, value| RESERVED_KEYS.include?(name) }
47
+ :values => options.reject { |name, _value| RESERVED_KEYS.include?(name) }
46
48
  }
47
49
  with_metadata(metadata) { super }
48
50
  end
49
51
 
50
- def interpolate(locale, entry, values = {})
52
+ def interpolate(locale, entry, values = EMPTY_HASH)
51
53
  metadata = entry.translation_metadata.merge(:original => entry)
52
54
  with_metadata(metadata) { super }
53
55
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # I18n Pluralization are useful when you want your application to
2
4
  # customize pluralization rules.
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  module Backend
3
5
  # A simple backend that reads translations from YAML files and stores them in
@@ -28,7 +30,7 @@ module I18n
28
30
  # This uses a deep merge for the translations hash, so existing
29
31
  # translations will be overwritten by new ones only at the deepest
30
32
  # level of the hash.
31
- def store_translations(locale, data, options = {})
33
+ def store_translations(locale, data, options = EMPTY_HASH)
32
34
  if I18n.enforce_available_locales &&
33
35
  I18n.available_locales_initialized? &&
34
36
  !I18n.available_locales.include?(locale.to_sym) &&
@@ -73,7 +75,7 @@ module I18n
73
75
  # nested translations hash. Splits keys or scopes containing dots
74
76
  # into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
75
77
  # <tt>%w(currency format)</tt>.
76
- def lookup(locale, key, scope = [], options = {})
78
+ def lookup(locale, key, scope = [], options = EMPTY_HASH)
77
79
  init_translations unless initialized?
78
80
  keys = I18n.normalize_keys(locale, key, scope, options[:separator])
79
81
 
@@ -1,4 +1,6 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
2
4
  module I18n
3
5
  module Backend
4
6
  module Transliterator
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  module I18n
@@ -57,7 +59,7 @@ module I18n
57
59
  @@available_locales = nil if @@available_locales.empty?
58
60
  @@available_locales_set = nil
59
61
  end
60
-
62
+
61
63
  # Returns true if the available_locales have been initialized
62
64
  def available_locales_initialized?
63
65
  ( !!defined?(@@available_locales) && !!@@available_locales )
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'cgi'
2
4
 
3
5
  module I18n
@@ -42,7 +44,7 @@ module I18n
42
44
  module Base
43
45
  attr_reader :locale, :key, :options
44
46
 
45
- def initialize(locale, key, options = {})
47
+ def initialize(locale, key, options = EMPTY_HASH)
46
48
  @key, @locale, @options = key, locale, options.dup
47
49
  options.each { |k, v| self.options[k] = v.inspect if v.is_a?(Proc) }
48
50
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  module Gettext
3
5
  PLURAL_SEPARATOR = "\001"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'i18n/gettext'
2
4
 
3
5
  module I18n
@@ -16,7 +18,7 @@ module I18n
16
18
  msgsid
17
19
  end
18
20
 
19
- def gettext(msgid, options = {})
21
+ def gettext(msgid, options = EMPTY_HASH)
20
22
  I18n.t(msgid, { :default => msgid, :separator => '|' }.merge(options))
21
23
  end
22
24
  alias _ gettext
@@ -28,7 +28,7 @@ module_eval <<'..end src/poparser.ry modeval..id7a99570e05', 'src/poparser.ry',
28
28
  ret.gsub!(/\\"/, "\"")
29
29
  ret
30
30
  end
31
-
31
+
32
32
  def parse(str, data, ignore_fuzzy = true)
33
33
  @comments = []
34
34
  @data = data
@@ -64,7 +64,7 @@ module_eval <<'..end src/poparser.ry modeval..id7a99570e05', 'src/poparser.ry',
64
64
  str = $'
65
65
  when /\A\#(.*)/
66
66
  @q.push [:COMMENT, $&]
67
- str = $'
67
+ str = $'
68
68
  when /\A\"(.*)\"/
69
69
  @q.push [:STRING, $1]
70
70
  str = $'
@@ -73,7 +73,7 @@ module_eval <<'..end src/poparser.ry modeval..id7a99570e05', 'src/poparser.ry',
73
73
  #@q.push [:STRING, c]
74
74
  str = str[1..-1]
75
75
  end
76
- end
76
+ end
77
77
  @q.push [false, '$end']
78
78
  if $DEBUG
79
79
  @q.each do |a,b|
@@ -88,7 +88,7 @@ module_eval <<'..end src/poparser.ry modeval..id7a99570e05', 'src/poparser.ry',
88
88
  end
89
89
  @data
90
90
  end
91
-
91
+
92
92
  def next_token
93
93
  @q.shift
94
94
  end
@@ -101,11 +101,11 @@ module_eval <<'..end src/poparser.ry modeval..id7a99570e05', 'src/poparser.ry',
101
101
  @comments.clear
102
102
  @msgctxt = ""
103
103
  end
104
-
104
+
105
105
  def on_comment(comment)
106
106
  @fuzzy = true if (/fuzzy/ =~ comment)
107
107
  @comments << comment
108
- end
108
+ end
109
109
 
110
110
 
111
111
  ..end src/poparser.ry modeval..id7a99570e05
@@ -245,7 +245,7 @@ module_eval <<'.,.,', 'src/poparser.ry', 25
245
245
 
246
246
  module_eval <<'.,.,', 'src/poparser.ry', 48
247
247
  def _reduce_8( val, _values, result )
248
- if @fuzzy and $ignore_fuzzy
248
+ if @fuzzy and $ignore_fuzzy
249
249
  if val[1] != ""
250
250
  $stderr.print _("Warning: fuzzy message was ignored.\n")
251
251
  $stderr.print " msgid '#{val[1]}'\n"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  module Locale
3
5
  autoload :Fallbacks, 'i18n/locale/fallbacks'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  class Middleware
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
4
  module Tests
3
5
  autoload :Basics, 'i18n/tests/basics'
@@ -104,9 +104,10 @@ module I18n
104
104
  end
105
105
 
106
106
  test "interpolation: given a translations containing a reserved key it raises I18n::ReservedInterpolationKey" do
107
- assert_raise(I18n::ReservedInterpolationKey) { interpolate(:default => '%{default}', :foo => :bar) }
108
- assert_raise(I18n::ReservedInterpolationKey) { interpolate(:default => '%{scope}', :foo => :bar) }
109
- assert_raise(I18n::ReservedInterpolationKey) { interpolate(:default => '%{separator}', :foo => :bar) }
107
+ assert_raise(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{exception_handler}') }
108
+ assert_raise(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{default}') }
109
+ assert_raise(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{separator}') }
110
+ assert_raise(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{scope}') }
110
111
  end
111
112
 
112
113
  test "interpolation: deep interpolation for default string" do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module I18n
2
- VERSION = "1.0.0"
4
+ VERSION = "1.0.1"
3
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sven Fuchs
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2018-02-14 00:00:00.000000000 Z
16
+ date: 2018-04-18 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: concurrent-ruby