mobility 1.0.7 → 1.1.3

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: ddbf8662456ee4b547ed3ead85fd44a3af486cbe94d85ad77679f811a7a5b98d
4
- data.tar.gz: 62fed63232e0bf182db5fdf9994ca3d2f50b61872b9e3c0bf4d1b4c7cf739698
3
+ metadata.gz: 225a8aa8a3eb8691e9a89d60fdd56509b47f7f36d22d1bb8d0c6f485f0e7cc2d
4
+ data.tar.gz: be10ccdea2727e568da790950b4df0633a543094543f7fd5f9c89154d5ea803e
5
5
  SHA512:
6
- metadata.gz: 449d4f885917546ffe9dab2678e39d597ecc340028e0e09293073487b8f8269ee097cea0b1ee28232cf04c05a1598d1e65be4d0be72b63b27f7e5cc543ab49bb
7
- data.tar.gz: 19f561713598217a2f8cf18aee0d906076086adf254995d7ddaccbd3e4d5b3db27f3d402f189d935538b1ef84d8e1fe33471af746a7c8d502095baa8f9cadd12
6
+ metadata.gz: 6f350d0a8e5fcf4f1804716f2cdfc0d500abd033ca0243e0c6be663adedf3ee192d785546a1be1274acbd5738533c7b5e3b9f8c48446e22bde39c26de8217819
7
+ data.tar.gz: 78fb7729118181d00e21f78c1144166916270e555bb4191c05a10cc660fb57d36b8af034cc7d42bfbd3d66d9509d1686f80554f85538b9a6d0fd488becd12966
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,6 +1,24 @@
1
1
  # Mobility Changelog
2
2
 
3
- ### Unreleased
3
+ ## Unreleased
4
+ - Assign blank values in pg hash backends
5
+ ([#516](https://github.com/shioyama/mobility/pull/516))
6
+
7
+ ## 1.1
8
+
9
+ ### 1.1.3
10
+ - Do not swallow keyword args on ruby 3 in fallthrough accessors
11
+ ([#520](https://github.com/shioyama/mobility/pull/520)) thanks
12
+ [doits](https://github.com/doits)!
13
+
14
+ ### 1.1.2
15
+ - Check whether class responds to mobility_attribute?
16
+ ([#515](https://github.com/shioyama/mobility/pull/515))
17
+
18
+ ### 1.1.1
19
+ - Updated signing key
20
+
21
+ ### 1.1.0
4
22
  - Remove `Mobility::Plugins::Attributes#each`
5
23
  ([#475](https://github.com/shioyama/mobility/pull/475))
6
24
  - Add public method `Mobility::Plugins::ActiveRecord::Query.build_query`
data/Gemfile CHANGED
@@ -12,8 +12,8 @@ group :development, :test do
12
12
  case orm_version
13
13
  when '4.2', '5.0', '5.1', '5.2', '6.0', '6.1'
14
14
  gem 'activerecord', "~> #{orm_version}.0"
15
- when '6.2'
16
- git 'https://github.com/rails/rails.git' do
15
+ when '7.0'
16
+ git 'https://github.com/rails/rails.git', branch: 'main' do
17
17
  gem 'activerecord'
18
18
  gem 'activesupport'
19
19
  end
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mobility (1.0.6)
4
+ mobility (1.1.2)
5
5
  i18n (>= 0.6.10, < 2)
6
6
  request_store (~> 1.0)
7
7
 
@@ -14,7 +14,7 @@ GEM
14
14
  concurrent-ruby (1.1.8)
15
15
  database_cleaner (1.99.0)
16
16
  diff-lcs (1.4.4)
17
- ffi (1.14.2)
17
+ ffi (1.15.0)
18
18
  formatador (0.2.5)
19
19
  guard (2.16.2)
20
20
  formatador (>= 0.2.4)
@@ -30,9 +30,9 @@ GEM
30
30
  guard (~> 2.1)
31
31
  guard-compat (~> 1.1)
32
32
  rspec (>= 2.99.0, < 4.0)
33
- i18n (1.8.8)
33
+ i18n (1.8.10)
34
34
  concurrent-ruby (~> 1.0)
35
- listen (3.4.1)
35
+ listen (3.5.1)
36
36
  rb-fsevent (~> 0.10, >= 0.10.3)
37
37
  rb-inotify (~> 0.9, >= 0.9.10)
38
38
  lumberjack (1.2.8)
@@ -68,7 +68,7 @@ GEM
68
68
  diff-lcs (>= 1.2.0, < 2.0)
69
69
  rspec-support (~> 3.10.0)
70
70
  rspec-support (3.10.2)
71
- sequel (5.41.0)
71
+ sequel (5.44.0)
72
72
  shellany (0.0.1)
73
73
  thor (1.1.0)
74
74
  yard (0.9.26)
data/README.md CHANGED
@@ -12,7 +12,7 @@ Mobility
12
12
  [docs]: http://www.rubydoc.info/gems/mobility
13
13
  [wiki]: https://github.com/shioyama/mobility/wiki
14
14
 
15
- **This is the readme for version 1.0 of Mobility. If you are using an earlier
15
+ **This is the readme for version 1.x of Mobility. If you are using an earlier
16
16
  version (0.8.x or earlier), you probably want the readme on the [0-8
17
17
  branch](https://github.com/shioyama/mobility/tree/0-8).**
18
18
 
@@ -52,17 +52,16 @@ section of the wiki.
52
52
  Installation
53
53
  ------------
54
54
 
55
- To use the latest pre-version of Mobility 1.0, add this line to your
56
- application's Gemfile:
55
+ Add this line to your application's Gemfile:
57
56
 
58
57
  ```ruby
59
- gem 'mobility', '~> 1.0.7'
58
+ gem 'mobility', '~> 1.1.3'
60
59
  ```
61
60
 
62
61
  ### ActiveRecord (Rails)
63
62
 
64
63
  Requirements:
65
- - ActiveRecord >= 5.0 (including 6.0)
64
+ - ActiveRecord >= 5.0 (including 6.x)
66
65
 
67
66
  (Support for most backends and features is also supported with
68
67
  ActiveRecord/Rails 4.2, but there are some tests still failing. To see exactly
@@ -131,9 +130,7 @@ default `type` option for the KeyValue backend to `:string`.
131
130
  end
132
131
  ```
133
132
 
134
- We will assume the configuration above in the examples that follow. Other
135
- configuration options are described in the [API
136
- docs](http://www.rubydoc.info/gems/mobility/Mobility/Configuration).
133
+ We will assume the configuration above in the examples that follow.
137
134
 
138
135
  See [Getting Started](#quickstart) to get started translating your models.
139
136
 
@@ -487,9 +484,7 @@ end
487
484
  ```
488
485
 
489
486
  Internally, Mobility assigns the fallbacks hash to an instance of
490
- `I18n::Locale::Fallbacks.new` (this can be customized by setting the
491
- `fallbacks_generator` configuration option, see the [API documentation on
492
- configuration](http://www.rubydoc.info/gems/mobility/Mobility/Configuration)).
487
+ `I18n::Locale::Fallbacks.new`.
493
488
 
494
489
  By setting fallbacks for German and French to Japanese, values will fall
495
490
  through to the Japanese value if none is present for either of these locales,
@@ -1029,6 +1024,9 @@ Integrations
1029
1024
  * [mobility-ransack](https://github.com/shioyama/mobility-ransack): Search
1030
1025
  attributes translated by Mobility with
1031
1026
  [Ransack](https://github.com/activerecord-hackery/ransack).
1027
+ * [mobility-actiontext](https://github.com/sedubois/mobility-actiontext): Translate
1028
+ Rails [Action Text](https://guides.rubyonrails.org/action_text_overview.html) rich text
1029
+ with Mobility.
1032
1030
 
1033
1031
  Tutorials
1034
1032
  ---------
data/lib/mobility.rb CHANGED
@@ -31,8 +31,9 @@ So the above example is equivalent to:
31
31
  `Mobility.translations_class` is a subclass of `Mobility::Translations` created
32
32
  when `Mobility.configure` is called to configure Mobility. In fact, when you
33
33
  call `Mobility.configure`, it is the subclass of `Mobility::Translations` which
34
- is passed to the block as `config`. Plugins and plugin configuration is all
35
- applied to the same `Mobility.translations_class`.
34
+ is passed to the block as `config` (or as `self` if no argument is passed to
35
+ the block). Plugins and plugin configuration is all applied to the same
36
+ `Mobility.translations_class`.
36
37
 
37
38
  There is another way to use Mobility, which is to create your own subclass or
38
39
  subclasses of +Mobility::Translations+ and include them explicitly, without
@@ -72,6 +73,9 @@ fallbacks plugin, whereas +Post+ uses +Translations+ which does not have that
72
73
  plugin enabled.
73
74
 
74
75
  =end
76
+
77
+ def ruby2_keywords(*); end unless respond_to?(:ruby2_keywords, true)
78
+
75
79
  module Mobility
76
80
  # A generic exception used by Mobility.
77
81
  class Error < StandardError
@@ -83,8 +87,6 @@ module Mobility
83
87
  require "mobility/plugins"
84
88
  require "mobility/translations"
85
89
 
86
- # General error for version compatibility conflicts
87
- class VersionNotSupportedError < ArgumentError; end
88
90
  CALL_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
89
91
  private_constant :CALL_COMPILABLE_REGEXP
90
92
 
@@ -201,6 +203,14 @@ module Mobility
201
203
  end
202
204
  end
203
205
 
206
+ # Check that a non-nil locale is valid. (Does not actually parse locale to
207
+ # check its format.)
208
+ # @raise [InvalidLocale] if locale is not a Symbol or not available
209
+ def validate_locale!(locale)
210
+ raise Mobility::InvalidLocale.new(locale) unless Symbol === locale
211
+ enforce_available_locales!(locale) if I18n.enforce_available_locales
212
+ end
213
+
204
214
  # Raises InvalidLocale exception if the locale passed in is present but not available.
205
215
  # @param [String,Symbol] locale
206
216
  # @raise [InvalidLocale] if locale is present but not available
@@ -217,7 +227,7 @@ module Mobility
217
227
  # simply default to +I18n.available_locales+, we may define many more
218
228
  # methods (in LocaleAccessors) than is really necessary.
219
229
  def available_locales
220
- if defined?(Rails) && Rails.application
230
+ if defined?(Rails) && Rails.respond_to?(:application) && Rails.application
221
231
  Rails.application.config.i18n.available_locales&.map(&:to_sym) || I18n.available_locales
222
232
  else
223
233
  I18n.available_locales
@@ -231,8 +241,8 @@ module Mobility
231
241
  end
232
242
 
233
243
  def set_locale(locale)
234
- locale = locale.to_sym if locale
235
- enforce_available_locales!(locale) if I18n.enforce_available_locales
244
+ locale = locale.to_sym if String === locale
245
+ validate_locale!(locale) if locale
236
246
  storage[:mobility_locale] = locale
237
247
  end
238
248
  end
@@ -17,8 +17,10 @@ On top of this, a backend will normally:
17
17
  - implement a +write+ instance method to write to the backend
18
18
  - implement an +each_locale+ instance method to iterate through available locales
19
19
  (used to define other +Enumerable+ traversal and search methods)
20
+ - implement a +valid_keys+ class method returning an array of symbols
21
+ corresponding to valid keys for configuring this backend.
20
22
  - implement a +configure+ class method to apply any normalization to the
21
- options hash
23
+ keys on the options hash included in +valid_keys+
22
24
  - call the +setup+ method yielding attributes and options to configure the
23
25
  model class
24
26
 
@@ -37,7 +37,6 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
37
37
  options[:association_name] ||= :"#{options[:type]}_translations"
38
38
  options[:class_name] ||= const_get("#{type.capitalize}Translation")
39
39
  end
40
- options[:table_alias_affix] = "#{model_class}_%s_#{options[:association_name]}"
41
40
  rescue NameError
42
41
  raise ArgumentError, "You must define a Mobility::Backends::ActiveRecord::KeyValue::#{type.capitalize}Translation class."
43
42
  end
@@ -49,7 +48,7 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
49
48
  # translation table value column
50
49
  def build_node(attr, locale)
51
50
  aliased_table = class_name.arel_table.alias(table_alias(attr, locale))
52
- Plugins::Arel::Attribute.new(aliased_table, :value, locale, self, attr.to_sym)
51
+ Plugins::Arel::Attribute.new(aliased_table, value_column, locale, self, attr.to_sym)
53
52
  end
54
53
 
55
54
  # Joins translations using either INNER/OUTER join appropriate to the query.
@@ -73,10 +72,10 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
73
72
  m = model_class.arel_table
74
73
  t = class_name.arel_table.alias(table_alias(key, locale))
75
74
  relation.joins(m.join(t, join_type).
76
- on(t[:key].eq(key).
75
+ on(t[key_column].eq(key).
77
76
  and(t[:locale].eq(locale).
78
- and(t[:translatable_type].eq(model_class.base_class.name).
79
- and(t[:translatable_id].eq(m[:id]))))).join_sources)
77
+ and(t[:"#{belongs_to}_type"].eq(model_class.base_class.name).
78
+ and(t[:"#{belongs_to}_id"].eq(m[:id]))))).join_sources)
80
79
  end
81
80
 
82
81
  def already_joined?(relation, name, locale, join_type)
@@ -151,8 +150,11 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
151
150
  end
152
151
 
153
152
  setup do |attributes, options|
154
- association_name = options[:association_name]
155
- translations_class = options[:class_name]
153
+ association_name = options[:association_name]
154
+ translation_class = options[:class_name]
155
+ key_column = options[:key_column]
156
+ value_column = options[:value_column]
157
+ belongs_to = options[:belongs_to]
156
158
 
157
159
  # Track all attributes for this association, so that we can limit the scope
158
160
  # of keys for the association to only these attributes. We need to track the
@@ -163,13 +165,13 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
163
165
  association_attributes = (instance_variable_get(:"@#{attrs_method_name}") || []) + attributes
164
166
  instance_variable_set(:"@#{attrs_method_name}", association_attributes)
165
167
 
166
- has_many association_name, ->{ where key: association_attributes },
167
- as: :translatable,
168
- class_name: translations_class.name,
169
- inverse_of: :translatable,
168
+ has_many association_name, ->{ where key_column => association_attributes },
169
+ as: belongs_to,
170
+ class_name: translation_class.name,
171
+ inverse_of: belongs_to,
170
172
  autosave: true
171
173
  before_save do
172
- send(association_name).select { |t| t.value.blank? }.each do |translation|
174
+ send(association_name).select { |t| t.send(value_column).blank? }.each do |translation|
173
175
  send(association_name).destroy(translation)
174
176
  end
175
177
  end
@@ -181,33 +183,32 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
181
183
  super(source)
182
184
  self.send("#{association_name}=", source.send(association_name).map(&:dup))
183
185
  # Set inverse on associations
184
- send(association_name).each { |translation| translation.translatable = self }
186
+ send(association_name).each do |translation|
187
+ translation.send(:"#{belongs_to}=", self)
188
+ end
185
189
  end
186
190
  end
187
191
  include const_set(module_name, callback_methods)
188
192
  end
189
193
 
190
- include DestroyKeyValueTranslations
194
+ # Ensure we only call after destroy hook once per translations class
195
+ translation_classes = [translation_class, *Mobility::Backends::ActiveRecord::KeyValue::Translation.descendants].uniq
196
+ after_destroy do
197
+ @mobility_after_destroy_translation_classes = [] unless defined?(@mobility_after_destroy_translation_classes)
198
+ (translation_classes - @mobility_after_destroy_translation_classes).each { |klass| klass.where(belongs_to => self).destroy_all }
199
+ @mobility_after_destroy_translation_classes += translation_classes
200
+ end
191
201
  end
192
202
 
193
203
  # Returns translation for a given locale, or builds one if none is present.
194
204
  # @param [Symbol] locale
195
205
  # @return [Mobility::Backends::ActiveRecord::KeyValue::TextTranslation,Mobility::Backends::ActiveRecord::KeyValue::StringTranslation]
196
206
  def translation_for(locale, **)
197
- translation = translations.find { |t| t.key == attribute && t.locale == locale.to_s }
198
- translation ||= translations.build(locale: locale, key: attribute)
199
- translation
200
- end
201
-
202
- module DestroyKeyValueTranslations
203
- def self.included(model_class)
204
- model_class.after_destroy do
205
- [:string, :text].each do |type|
206
- Mobility::Backends::ActiveRecord::KeyValue.const_get("#{type.capitalize}Translation").
207
- where(translatable: self).destroy_all
208
- end
209
- end
207
+ translation = translations.find do |t|
208
+ t.send(key_column) == attribute && t.locale == locale.to_s
210
209
  end
210
+ translation ||= translations.build(locale: locale, key_column => attribute)
211
+ translation
211
212
  end
212
213
 
213
214
  class Translation < ::ActiveRecord::Base
@@ -32,7 +32,7 @@ Internal class used by ActiveRecord backends backed by a Postgres data type
32
32
  def self.dump(obj)
33
33
  if obj.is_a? ::Hash
34
34
  obj.inject({}) do |translations, (locale, value)|
35
- translations[locale] = value if value.present?
35
+ translations[locale] = value unless value.nil?
36
36
  translations
37
37
  end
38
38
  else
@@ -55,18 +55,18 @@ other backends on model (otherwise one will overwrite the other).
55
55
  # @!group Backend Accessors
56
56
  # @!macro backend_reader
57
57
  def read(locale, **options)
58
- translation_for(locale, **options).value
58
+ translation_for(locale, **options).send(value_column)
59
59
  end
60
60
 
61
61
  # @!macro backend_writer
62
62
  def write(locale, value, **options)
63
- translation_for(locale, **options).value = value
63
+ translation_for(locale, **options).send(:"#{value_column}=", value)
64
64
  end
65
65
  # @!endgroup
66
66
 
67
67
  # @!macro backend_iterator
68
68
  def each_locale
69
- translations.each { |t| yield(t.locale.to_sym) if t.key == attribute }
69
+ translations.each { |t| yield(t.locale.to_sym) if t.send(key_column) == attribute }
70
70
  end
71
71
 
72
72
  private
@@ -79,12 +79,14 @@ other backends on model (otherwise one will overwrite the other).
79
79
  backend_class.extend ClassMethods
80
80
  backend_class.option_reader :association_name
81
81
  backend_class.option_reader :class_name
82
- backend_class.option_reader :table_alias_affix
82
+ backend_class.option_reader :key_column
83
+ backend_class.option_reader :value_column
84
+ backend_class.option_reader :belongs_to
83
85
  end
84
86
 
85
87
  module ClassMethods
86
88
  def valid_keys
87
- [:type, :association_name, :class_name]
89
+ [:type, :association_name, :class_name, :key_column, :value_column, :belongs_to]
88
90
  end
89
91
 
90
92
  # @!group Backend Configuration
@@ -99,6 +101,9 @@ other backends on model (otherwise one will overwrite the other).
99
101
  options[:type] &&= options[:type].to_sym
100
102
  options[:association_name] &&= options[:association_name].to_sym
101
103
  options[:class_name] &&= Util.constantize(options[:class_name])
104
+ options[:key_column] ||= :key
105
+ options[:value_column] ||= :value
106
+ options[:belongs_to] ||= :translatable
102
107
  if !(options[:type] || (options[:class_name] && options[:association_name]))
103
108
  raise ArgumentError, "KeyValue backend requires an explicit type option, either text or string."
104
109
  end
@@ -110,7 +115,7 @@ other backends on model (otherwise one will overwrite the other).
110
115
  end
111
116
 
112
117
  def table_alias(attr, locale)
113
- table_alias_affix % "#{attr}_#{Mobility.normalize_locale(locale)}"
118
+ "#{model_class}_#{attr}_#{Mobility.normalize_locale(locale)}_#{options[:association_name]}"
114
119
  end
115
120
  end
116
121
 
@@ -32,14 +32,13 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
32
32
  options[:association_name] ||= :"#{options[:type]}_translations"
33
33
  options[:class_name] ||= const_get("#{type.capitalize}Translation")
34
34
  end
35
- options[:table_alias_affix] = "#{model_class}_%s_#{options[:association_name]}"
36
35
  rescue NameError
37
36
  raise ArgumentError, "You must define a Mobility::Sequel::#{type.capitalize}Translation class."
38
37
  end
39
38
  # @!endgroup
40
39
 
41
40
  def build_op(attr, locale)
42
- QualifiedIdentifier.new(table_alias(attr, locale), :value, locale, self, attr)
41
+ QualifiedIdentifier.new(table_alias(attr, locale), value_column, locale, self, attr)
43
42
  end
44
43
 
45
44
  # @param [Sequel::Dataset] dataset Dataset to prepare
@@ -58,10 +57,10 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
58
57
  dataset.join_table(join_type,
59
58
  class_name.table_name,
60
59
  {
61
- key: attr.to_s,
62
- locale: locale.to_s,
63
- translatable_type: model_class.name,
64
- translatable_id: ::Sequel[:"#{model_class.table_name}"][:id]
60
+ key_column => attr.to_s,
61
+ :locale => locale.to_s,
62
+ :"#{belongs_to}_type" => model_class.name,
63
+ :"#{belongs_to}_id" => ::Sequel[:"#{model_class.table_name}"][:id]
65
64
  },
66
65
  table_alias: table_alias(attr, locale))
67
66
  end
@@ -127,27 +126,37 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
127
126
  backend = self
128
127
 
129
128
  setup do |attributes, options|
130
- association_name = options[:association_name]
131
- translations_class = options[:class_name]
132
-
129
+ association_name = options[:association_name]
130
+ translation_class = options[:class_name]
131
+ key_column = options[:key_column]
132
+ value_column = options[:value_column]
133
+ belongs_to = options[:belongs_to]
134
+ belongs_to_id = :"#{belongs_to}_id"
135
+ belongs_to_type = :"#{belongs_to}_type"
136
+
137
+ # Track all attributes for this association, so that we can limit the scope
138
+ # of keys for the association to only these attributes. We need to track the
139
+ # attributes assigned to the association in case this setup code is called
140
+ # multiple times, so we don't "forget" earlier attributes.
141
+ #
133
142
  attrs_method_name = :"#{association_name}_attributes"
134
143
  association_attributes = (instance_variable_get(:"@#{attrs_method_name}") || []) + attributes
135
144
  instance_variable_set(:"@#{attrs_method_name}", association_attributes)
136
145
 
137
146
  one_to_many association_name,
138
- reciprocal: :translatable,
139
- key: :translatable_id,
147
+ reciprocal: belongs_to,
148
+ key: belongs_to_id,
140
149
  reciprocal_type: :one_to_many,
141
- conditions: { translatable_type: self.to_s, key: association_attributes },
142
- adder: proc { |translation| translation.update(translatable_id: pk, translatable_type: self.class.to_s) },
143
- remover: proc { |translation| translation.update(translatable_id: nil, translatable_type: nil) },
144
- clearer: proc { send(:"#{association_name}_dataset").update(translatable_id: nil, translatable_type: nil) },
145
- class: translations_class
150
+ conditions: { belongs_to_type => self.to_s, key_column => association_attributes },
151
+ adder: proc { |translation| translation.update(belongs_to_id => pk, belongs_to_type => self.class.to_s) },
152
+ remover: proc { |translation| translation.update(belongs_to_id => nil, belongs_to_type => nil) },
153
+ clearer: proc { send_(:"#{association_name}_dataset").update(belongs_to_id => nil, belongs_to_type => nil) },
154
+ class: translation_class
146
155
 
147
156
  callback_methods = Module.new do
148
157
  define_method :before_save do
149
158
  super()
150
- send(association_name).select { |t| attributes.include?(t.key) && Util.blank?(t.value) }.each(&:destroy)
159
+ send(association_name).select { |t| attributes.include?(t.__send__(key_column)) && Util.blank?(t.__send__(value_column)) }.each(&:destroy)
151
160
  end
152
161
  define_method :after_save do
153
162
  super()
@@ -156,7 +165,17 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
156
165
  end
157
166
  include callback_methods
158
167
 
159
- include DestroyKeyValueTranslations
168
+ # Clean up *all* leftover translations of this model, only once.
169
+ translation_classes = [translation_class, *Mobility::Backends::Sequel::KeyValue::Translation.descendants].uniq
170
+ define_method :after_destroy do
171
+ super()
172
+
173
+ @mobility_after_destroy_translation_classes = [] unless defined?(@mobility_after_destroy_translation_classes)
174
+ (translation_classes - @mobility_after_destroy_translation_classes).each do |klass|
175
+ klass.where(belongs_to_id => id, belongs_to_type => self.class.name).destroy
176
+ end
177
+ @mobility_after_destroy_translation_classes += translation_classes
178
+ end
160
179
  include(mod = Module.new)
161
180
  backend.define_column_changes(mod, attributes)
162
181
  end
@@ -165,30 +184,19 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
165
184
  # @param [Symbol] locale
166
185
  # @return [Mobility::Backends::Sequel::KeyValue::TextTranslation,Mobility::Backends::Sequel::KeyValue::StringTranslation]
167
186
  def translation_for(locale, **)
168
- translation = model.send(association_name).find { |t| t.key == attribute && t.locale == locale.to_s }
169
- translation ||= class_name.new(locale: locale, key: attribute)
187
+ translation = model.send(association_name).find { |t| t.__send__(key_column) == attribute && t.locale == locale.to_s }
188
+ translation ||= class_name.new(locale: locale, key_column => attribute)
170
189
  translation
171
190
  end
172
191
 
173
192
  # Saves translation which have been built and which have non-blank values.
174
193
  def save_translations
175
194
  cache.each_value do |translation|
176
- next unless present?(translation.value)
195
+ next unless present?(translation.__send__ value_column)
177
196
  translation.id ? translation.save : model.send("add_#{singularize(association_name)}", translation)
178
197
  end
179
198
  end
180
199
 
181
- # Clean up *all* leftover translations of this model, only once.
182
- module DestroyKeyValueTranslations
183
- def after_destroy
184
- super
185
- [:string, :text].freeze.each do |type|
186
- Mobility::Backends::Sequel::KeyValue.const_get("#{type.capitalize}Translation").
187
- where(translatable_id: id, translatable_type: self.class.name).destroy
188
- end
189
- end
190
- end
191
-
192
200
  class CacheRequired < ::StandardError; end
193
201
 
194
202
  module Cache
@@ -212,8 +220,32 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
212
220
  end
213
221
  end
214
222
 
215
- module Translation
216
- def self.included(base)
223
+ class Translatable < Module
224
+ attr_reader :key_column, :value_column, :belongs_to, :id_column, :type_column
225
+
226
+ def initialize(key_column, value_column, belongs_to)
227
+ @key_column = key_column
228
+ @value_column = value_column
229
+ @belongs_to = belongs_to
230
+ @id_column = :"#{belongs_to}_id"
231
+ @type_column = :"#{belongs_to}_type"
232
+ end
233
+
234
+ # Strictly these are not "descendants", but to keep terminology
235
+ # consistent with ActiveRecord KeyValue backend.
236
+ def descendants
237
+ @descendants ||= Set.new
238
+ end
239
+
240
+ def included(base)
241
+ @descendants ||= Set.new
242
+ @descendants << base
243
+
244
+ mod = self
245
+ key_column = mod.key_column
246
+ id_column = mod.id_column
247
+ type_column = mod.type_column
248
+
217
249
  base.class_eval do
218
250
  plugin :validation_helpers
219
251
 
@@ -221,16 +253,16 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
221
253
  #
222
254
  model = underscore(self.to_s)
223
255
  plural_model = pluralize(model)
224
- many_to_one :translatable,
256
+ many_to_one mod.belongs_to,
225
257
  reciprocal: plural_model.to_sym,
226
258
  reciprocal_type: :many_to_one,
227
259
  setter: (proc do |able_instance|
228
- self[:translatable_id] = (able_instance.pk if able_instance)
229
- self[:translatable_type] = (able_instance.class.name if able_instance)
260
+ self[id_column] = (able_instance.pk if able_instance)
261
+ self[type_column] = (able_instance.class.name if able_instance)
230
262
  end),
231
263
  dataset: (proc do
232
- translatable_type = send :translatable_type
233
- translatable_id = send :translatable_id
264
+ translatable_type = send type_column
265
+ translatable_id = send id_column
234
266
  return if translatable_type.nil? || translatable_id.nil?
235
267
  klass = self.class.send(:constantize, translatable_type)
236
268
  klass.where(klass.primary_key => translatable_id)
@@ -238,29 +270,30 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
238
270
  eager_loader: (proc do |eo|
239
271
  id_map = {}
240
272
  eo[:rows].each do |model|
241
- model_able_type = model.send :translatable_type
242
- model_able_id = model.send :translatable_id
243
- model.associations[:translatable] = nil
273
+ model_able_type = model.send type_column
274
+ model_able_id = model.send id_column
275
+ model.associations[belongs_to] = nil
244
276
  ((id_map[model_able_type] ||= {})[model_able_id] ||= []) << model if !model_able_type.nil? && !model_able_id.nil?
245
277
  end
246
278
  id_map.each do |klass_name, id_map|
247
279
  klass = constantize(camelize(klass_name))
248
280
  klass.where(klass.primary_key=>id_map.keys).all do |related_obj|
249
281
  id_map[related_obj.pk].each do |model|
250
- model.associations[:translatable] = related_obj
282
+ model.associations[belongs_to] = related_obj
251
283
  end
252
284
  end
253
285
  end
254
286
  end)
255
287
 
256
- def validate
257
- super
258
- validates_presence [:locale, :key, :translatable_id, :translatable_type]
259
- validates_unique [:locale, :key, :translatable_id, :translatable_type]
288
+ define_method :validate do
289
+ super()
290
+ validates_presence [:locale, key_column, id_column, type_column]
291
+ validates_unique [:locale, key_column, id_column, type_column]
260
292
  end
261
293
  end
262
294
  end
263
295
  end
296
+ Translation = Translatable.new(:key, :value, :translatable)
264
297
 
265
298
  class TextTranslation < ::Sequel::Model(:mobility_text_translations)
266
299
  include Translation
@@ -41,7 +41,7 @@ jsonb).
41
41
  mod = Module.new do
42
42
  define_method :before_validation do
43
43
  columns.each do |column|
44
- self[column].delete_if { |_, v| Util.blank?(v) }
44
+ self[column].delete_if { |_, v| v.nil? }
45
45
  end
46
46
  super()
47
47
  end
@@ -40,7 +40,7 @@ Format for serialization. Either +:yaml+ (default) or +:json+.
40
40
  return if obj.nil?
41
41
  if obj.is_a? ::Hash
42
42
  obj = obj.inject({}) do |translations, (locale, value)|
43
- translations[locale] = value.to_s if Util.present?(value)
43
+ translations[locale] = value.to_s unless value.nil?
44
44
  translations
45
45
  end
46
46
  else
@@ -8,7 +8,9 @@ require_relative "./active_record/uniqueness_validation"
8
8
  module Mobility
9
9
  =begin
10
10
 
11
- Plugin for ActiveRecord models.
11
+ Plugin for ActiveRecord models. This plugin automatically requires activerecord
12
+ related plugins, which are not actually "active" unless their base plugin (e.g.
13
+ dirty for active_record_dirty) is also enabled.
12
14
 
13
15
  =end
14
16
  module Plugins
@@ -3,6 +3,11 @@
3
3
  module Mobility
4
4
  module Plugins
5
5
  module ActiveRecord
6
+ =begin
7
+
8
+ Maps backend names to ActiveRecord namespaced backends.
9
+
10
+ =end
6
11
  module Backend
7
12
  extend Plugin
8
13
 
@@ -29,7 +29,9 @@ enabled for any one attribute on the model.
29
29
  klass.class_eval do
30
30
  extend QueryMethod
31
31
  extend FindByMethods.new(*plugin.names)
32
- singleton_class.send :alias_method, plugin.query_method, :__mobility_query_scope__
32
+ singleton_class.define_method(plugin.query_method) do |locale: Mobility.locale, &block|
33
+ Query.build_query(self, locale, &block)
34
+ end
33
35
  end
34
36
  backend_class.include BackendMethods
35
37
  end
@@ -39,6 +41,14 @@ enabled for any one attribute on the model.
39
41
  def attribute_alias(attribute, locale = Mobility.locale)
40
42
  "__mobility_%s_%s__" % [attribute, ::Mobility.normalize_locale(locale)]
41
43
  end
44
+
45
+ def build_query(klass, locale = Mobility.locale, &block)
46
+ if block_given?
47
+ VirtualRow.build_query(klass, locale, &block)
48
+ else
49
+ klass.all.extending(QueryExtension)
50
+ end
51
+ end
42
52
  end
43
53
 
44
54
  module BackendMethods
@@ -57,13 +67,9 @@ enabled for any one attribute on the model.
57
67
  end
58
68
 
59
69
  module QueryMethod
60
- # This is required for UniquenessValidator.
61
70
  def __mobility_query_scope__(locale: Mobility.locale, &block)
62
- if block_given?
63
- VirtualRow.build_query(self, locale, &block)
64
- else
65
- all.extending(QueryExtension)
66
- end
71
+ warn '__mobility_query_scope__ is an internal method and will be deprecated in the next release.'
72
+ Query.build_query(self, locale, &block)
67
73
  end
68
74
  end
69
75
 
@@ -71,18 +77,21 @@ enabled for any one attribute on the model.
71
77
  # an instance-eval'ed block. Inspired by Sequel's (much more
72
78
  # sophisticated) virtual rows.
73
79
  class VirtualRow < BasicObject
74
- attr_reader :__backends
80
+ attr_reader :backends, :locales
75
81
 
76
- def initialize(model_class, locale)
77
- @model_class, @locale, @__backends = model_class, locale, []
82
+ def initialize(klass, global_locale)
83
+ @klass, @global_locale, @locales, @backends = klass, global_locale, [], []
78
84
  end
79
85
 
80
- def method_missing(m, *)
81
- if @model_class.mobility_attribute?(m)
82
- @__backends |= [@model_class.mobility_backend_class(m)]
83
- @model_class.mobility_backend_class(m).build_node(m, @locale)
84
- elsif @model_class.column_names.include?(m.to_s)
85
- @model_class.arel_table[m]
86
+ def method_missing(m, *args)
87
+ if @klass.mobility_attribute?(m)
88
+ @backends |= [@klass.mobility_backend_class(m)]
89
+ ::Mobility.validate_locale!(args[0]) if args[0]
90
+ locale = args[0] || @global_locale
91
+ @locales |= [locale]
92
+ @klass.mobility_backend_class(m).build_node(m, locale)
93
+ elsif @klass.column_names.include?(m.to_s)
94
+ @klass.arel_table[m]
86
95
  else
87
96
  super
88
97
  end
@@ -90,21 +99,27 @@ enabled for any one attribute on the model.
90
99
 
91
100
  class << self
92
101
  def build_query(klass, locale, &block)
102
+ ::Mobility.validate_locale!(locale)
103
+
93
104
  row = new(klass, locale)
94
105
  query = block.arity.zero? ? row.instance_eval(&block) : block.call(row)
95
106
 
96
107
  if ::ActiveRecord::Relation === query
97
108
  predicates = query.arel.constraints
98
- apply_scopes(klass.all, row.__backends, locale, predicates).merge(query)
109
+ apply_scopes(klass.all, row.backends, row.locales, predicates).merge(query)
99
110
  else
100
- apply_scopes(klass.all, row.__backends, locale, query).where(query)
111
+ apply_scopes(klass.all, row.backends, row.locales, query).where(query)
101
112
  end
102
113
  end
103
114
 
104
115
  private
105
116
 
106
- def apply_scopes(scope, backends, locale, predicates)
107
- backends.inject(scope) { |r, b| b.apply_scope(r, predicates, locale) }
117
+ def apply_scopes(scope, backends, locales, predicates)
118
+ backends.inject(scope) do |scope_, b|
119
+ locales.inject(scope_) do |r, locale|
120
+ b.apply_scope(r, predicates, locale)
121
+ end
122
+ end
108
123
  end
109
124
  end
110
125
  end
@@ -122,6 +137,8 @@ enabled for any one attribute on the model.
122
137
  end
123
138
 
124
139
  def order(opts, *rest)
140
+ return super unless @klass.respond_to?(:mobility_attribute?)
141
+
125
142
  case opts
126
143
  when Symbol, String
127
144
  @klass.mobility_attribute?(opts) ? order({ opts => :asc }, *rest) : super
@@ -146,6 +163,9 @@ enabled for any one attribute on the model.
146
163
  define_method method_name do |*attrs, &block|
147
164
  return super(*attrs, &block) if (method_name == 'select' && block.present?)
148
165
 
166
+ if ::ActiveRecord::VERSION::STRING < '7.0'
167
+ return super(*attrs, &block) unless @klass.respond_to?(:mobility_attribute?)
168
+ end
149
169
  return super(*attrs, &block) unless attrs.any?(&@klass.method(:mobility_attribute?))
150
170
 
151
171
  keys = attrs.dup
@@ -27,7 +27,7 @@ module Mobility
27
27
 
28
28
  if ([*options[:scope]] + [attribute]).any? { |name| klass.mobility_attribute?(name) }
29
29
  return unless value.present?
30
- relation = klass.unscoped.__mobility_query_scope__ do |m|
30
+ relation = Plugins::ActiveRecord::Query.build_query(klass.unscoped, Mobility.locale) do |m|
31
31
  node = m.__send__(attribute)
32
32
  options[:case_sensitive] == false ? node.lower.eq(value.downcase) : node.eq(value)
33
33
  end
@@ -50,7 +50,7 @@ module Mobility
50
50
 
51
51
  def mobility_scope_relation(record, relation)
52
52
  [*options[:scope]].inject(relation) do |scoped_relation, scope_item|
53
- scoped_relation.__mobility_query_scope__ do |m|
53
+ Plugins::ActiveRecord::Query.build_query(scoped_relation, Mobility.locale) do |m|
54
54
  m.__send__(scope_item).eq(record.send(scope_item))
55
55
  end
56
56
  end
@@ -19,12 +19,6 @@ for aggregating attributes.
19
19
  @names = names.map(&:to_s).freeze
20
20
  end
21
21
 
22
- # Yield each attribute name to block
23
- # @yieldparam [String] Attribute
24
- def each &block
25
- names.each(&block)
26
- end
27
-
28
22
  # Show useful information about this module.
29
23
  # @return [String]
30
24
  def inspect
@@ -55,6 +55,13 @@ model class is generated.
55
55
  end
56
56
  end
57
57
 
58
+ # Following is needed in order to not swallow `kwargs` on ruby >= 3.0.
59
+ # Otherwise `kwargs` are not passed by `super` to a possible other
60
+ # `method_missing` defined like this:
61
+ #
62
+ # def method_missing(name, *args, **kwargs, &block); end
63
+ ruby2_keywords :method_missing
64
+
58
65
  define_method :respond_to_missing? do |method_name, include_private = false|
59
66
  (method_name =~ method_name_regex) || super(method_name, include_private)
60
67
  end
@@ -1,5 +1,4 @@
1
1
  require "sequel"
2
- raise VersionNotSupportedError, "Mobility is only compatible with Sequel 4.0 and greater" if ::Sequel::MAJOR < 4
3
2
  require "sequel/plugins/mobility"
4
3
  unless defined?(ActiveSupport::Inflector)
5
4
  # TODO: avoid automatically including the inflector extension
@@ -13,6 +12,13 @@ require_relative "./sequel/query"
13
12
 
14
13
  module Mobility
15
14
  module Plugins
15
+ =begin
16
+
17
+ Plugin for Sequel models. This plugin automatically requires sequel related
18
+ plugins, which are not actually "active" unless their base plugin (e.g. dirty
19
+ for sequel_dirty) is also enabled.
20
+
21
+ =end
16
22
  module Sequel
17
23
  extend Plugin
18
24
 
@@ -1,6 +1,11 @@
1
1
  module Mobility
2
2
  module Plugins
3
3
  module Sequel
4
+ =begin
5
+
6
+ Maps backend names to Sequel namespaced backends.
7
+
8
+ =end
4
9
  module Backend
5
10
  extend Plugin
6
11
 
@@ -3,7 +3,8 @@ module Mobility
3
3
  module Plugins
4
4
  =begin
5
5
 
6
- See ActiveRecord::Query plugin.
6
+ Supports querying on Sequel model translated attributes. Similar API to the
7
+ ActiveRecord query plugin.
7
8
 
8
9
  =end
9
10
  module Sequel
@@ -19,35 +20,47 @@ See ActiveRecord::Query plugin.
19
20
 
20
21
  klass.class_eval do
21
22
  extend QueryMethod
22
- singleton_class.send :alias_method, plugin.query_method, :__mobility_query_dataset__
23
+ singleton_class.define_method(plugin.query_method) do |locale: Mobility.locale, &block|
24
+ Query.build_query(self, locale, &block)
25
+ end
23
26
  end
24
27
  end
25
28
  end
26
29
 
27
- module QueryMethod
28
- def __mobility_query_dataset__(locale: Mobility.locale, &block)
30
+ class << self
31
+ def build_query(klass, locale = Mobility.locale, &block)
29
32
  if block_given?
30
- VirtualRow.build_query(self, locale, &block)
33
+ VirtualRow.build_query(klass, locale, &block)
31
34
  else
32
- dataset.with_extend(QueryExtension)
35
+ klass.dataset.with_extend(QueryExtension)
33
36
  end
34
37
  end
35
38
  end
36
39
 
40
+ module QueryMethod
41
+ def __mobility_query_dataset__(locale: Mobility.locale, &block)
42
+ warn '__mobility_query_dataset__ is an internal method and will be deprecated in the next release.'
43
+ Query.build_query(self, locale, &block)
44
+ end
45
+ end
46
+
37
47
  # Internal class to create a "clean room" for manipulating translated
38
48
  # attribute nodes in an instance-eval'ed block. Inspired by Sequel's
39
49
  # (much more sophisticated) virtual rows.
40
50
  class VirtualRow < BasicObject
41
- attr_reader :__backends
51
+ attr_reader :backends, :locales
42
52
 
43
- def initialize(model_class, locale)
44
- @model_class, @locale, @__backends = model_class, locale, []
53
+ def initialize(model_class, global_locale)
54
+ @model_class, @global_locale, @backends, @locales = model_class, global_locale, [], []
45
55
  end
46
56
 
47
- def method_missing(m, *)
57
+ def method_missing(m, *args)
48
58
  if @model_class.mobility_attribute?(m)
49
- @__backends |= [@model_class.mobility_backend_class(m)]
50
- @model_class.mobility_backend_class(m).build_op(m.to_s, @locale)
59
+ @backends |= [@model_class.mobility_backend_class(m)]
60
+ ::Mobility.validate_locale!(args[0]) if args[0]
61
+ locale = args[0] || @global_locale
62
+ @locales |= [locale]
63
+ @model_class.mobility_backend_class(m).build_op(m.to_s, locale)
51
64
  elsif @model_class.columns.include?(m.to_s)
52
65
  ::Sequel::SQL::QualifiedIdentifier.new(@model_class.table_name, m)
53
66
  else
@@ -57,21 +70,27 @@ See ActiveRecord::Query plugin.
57
70
 
58
71
  class << self
59
72
  def build_query(klass, locale, &block)
73
+ ::Mobility.validate_locale!(locale)
74
+
60
75
  row = new(klass, locale)
61
76
  query = block.arity.zero? ? row.instance_eval(&block) : block.call(row)
62
77
 
63
78
  if ::Sequel::Dataset === query
64
79
  predicates = query.opts[:where]
65
- prepare_datasets(query, row.__backends, locale, predicates)
80
+ prepare_datasets(query, row.backends, row.locales, predicates)
66
81
  else
67
- prepare_datasets(klass.dataset, row.__backends, locale, query).where(query)
82
+ prepare_datasets(klass.dataset, row.backends, row.locales, query).where(query)
68
83
  end
69
84
  end
70
85
 
71
86
  private
72
87
 
73
- def prepare_datasets(dataset, backends, locale, predicates)
74
- backends.inject(dataset) { |ds, b| b.prepare_dataset(ds, predicates, locale) }
88
+ def prepare_datasets(dataset, backends, locales, predicates)
89
+ backends.inject(dataset) do |dataset_, b|
90
+ locales.inject(dataset_) do |ds, locale|
91
+ b.prepare_dataset(ds, predicates, locale)
92
+ end
93
+ end
75
94
  end
76
95
  end
77
96
  end
@@ -7,8 +7,8 @@ module Mobility
7
7
 
8
8
  module VERSION
9
9
  MAJOR = 1
10
- MINOR = 0
11
- TINY = 7
10
+ MINOR = 1
11
+ TINY = 3
12
12
  PRE = nil
13
13
 
14
14
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mobility
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Salzberg
@@ -11,30 +11,30 @@ cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
13
  MIIEODCCAqCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAjMSEwHwYDVQQDDBhjaHJp
14
- cy9EQz1kZWppbXN0YS9EQz1jb20wHhcNMjAwMjExMDEwMjM1WhcNMjEwMjEwMDEw
15
- MjM1WjAjMSEwHwYDVQQDDBhjaHJpcy9EQz1kZWppbXN0YS9EQz1jb20wggGiMA0G
16
- CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC99crJF+gE4WQnN7S4xdacGpZWg7hZ
17
- UlXPXM1vX4HVaw8essO6eNGafYqKRQKf3WDW4uM6kqPd4OZTfahGhocVtVScJYGi
18
- 5SRuw9rrJeFlojUkCSqy47on7t858OebbD28eo71sZLTclGmza6UpjiLZqy0AL4P
19
- 9dkK2j9pQJ3jYTNYteq7P6A109ExSGWbaRvkAKU+vTMJsK5MW2bWullsOGHrZiPW
20
- 7PXAaU33X29ddLu/zj/4qe83GVvnrprjw5RRgoQgP0Umw8zKG50XB7nS3TAUiaRz
21
- oD+eKgOIeZpPRwemINf0VsP1L+/FnUS6BkzVCOV9MWhUbrkdxCHLrSB8JL4ooXXR
22
- N/J4KlR5xpv6b+z+i2lScfkrH7r9RF4ZtpiDQzyCxvuIZOQTzUneUSzMIk9BaEN2
23
- 5S19cDUjW5fi75npJ+YnrUN83Ta3sa/Pp4dnUqiBK7WHBDnHMN6j7iASoAjKVTgM
24
- 8F/xjk4qgxA7vjv2obj2zv65CknnQprLCpMCAwEAAaN3MHUwCQYDVR0TBAIwADAL
25
- BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFOO4919GTuKTQA2Klo2QO3jGlbJTMB0GA1Ud
26
- EQQWMBSBEmNocmlzQGRlamltc3RhLmNvbTAdBgNVHRIEFjAUgRJjaHJpc0BkZWpp
27
- bXN0YS5jb20wDQYJKoZIhvcNAQELBQADggGBADfIFBldH77wyUv2RZ1kwvuvRvpL
28
- RNFdQlCbuVSn3abRAmc9rIsh80syhjWjYnml3guf+g2tYB1rU3NeTFRVupdvcUWJ
29
- T6mITUeDHpNoxF6KAp3zSsdoBoEHdOBNH7Jpxp+L3a2LZ0k6fW12xEafmymOD3fp
30
- BmIrE2Vr9aUec2Sk4fbKEYqsxhmXx+o8kKU7tnxVYMv4cX5X3yo45FA7Rh2JQuub
31
- MBT+NALoYFaSTHWIr/4tAolWVt8NNGUKEokaFjjf5gAGM6piq6ohTHl5dCtcEPX1
32
- klHOa2pIFwuUAWoVCpZa9XzRV5qz+mUrU70DF9dX6Cotv/sKOIxiGvQLnwzlSQWH
33
- iXMqkM6Y5FSwViOQy4U2egDDSTB5a16iAnN7/qzqex6SYTsQdSmyc0mWCb9rkIoF
34
- gSQml7TqcC6dZRsZRwYqzD9kUwdAJoCqno2CBUKs2l0yQAjFT36lRrVJznb7uWwa
35
- xpPFnsrtyaZW6Dty8TSG3qzmeGpmpIotA8x1VA==
14
+ cy9EQz1kZWppbWF0YS9EQz1jb20wHhcNMjEwMjE4MTMxMzA5WhcNMjIwMjE4MTMx
15
+ MzA5WjAjMSEwHwYDVQQDDBhjaHJpcy9EQz1kZWppbWF0YS9EQz1jb20wggGiMA0G
16
+ CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDURCKbt5oY0sCp4kYK1u5SLzVHg6Q1
17
+ 2LejeQvUGpR3gulWqrq/507XRxE/9FSpLfgo3cGGYio1/gg2Yp7pBI4ZNEz8d2Vg
18
+ 6caWLHYtHYF0/jlo177UspEF1bt3lCCmaA/ZyQpvoLi76Jf6VCBjepMqhLjeBSsA
19
+ xUqSdgNT8lzduOzdYk/GWf2Trvyz72IN6rY7hSwJ/U4R2DusRNTbKC55iyu0MyqI
20
+ Nks33les0xQERucqes1YzSEnpott/GUQ/fFWV1Qx7M1hMnqbQIm493BueR6X95a2
21
+ B7/aqY7LUVVmn9p65NMBJhbbP/pbAcLYV0C+y1Jy9NaVQTpWmJXVKBpYwlAzOJOQ
22
+ +b/7MBzT5Zzudkq9OlA5rZJB0hFo/Bm38MOCTSTk1/RT+zmoOyb4bx/h400L4ZUt
23
+ bRGON33BZ99gPiYdGfd3Pc/7FooteJASjKIO4Hman2ELRIdu6Bq+fIkTdJBcruS/
24
+ XL6xoRitCG7CX0IqmMKuLiKA/J0amAikHGsCAwEAAaN3MHUwCQYDVR0TBAIwADAL
25
+ BgNVHQ8EBAMCBLAwHQYDVR0OBBYEFMNUGAhS68egZT6DOfJwrfIdCtT/MB0GA1Ud
26
+ EQQWMBSBEmNocmlzQGRlamltYXRhLmNvbTAdBgNVHRIEFjAUgRJjaHJpc0BkZWpp
27
+ bWF0YS5jb20wDQYJKoZIhvcNAQELBQADggGBAH1RnWhD9bum/ijqzAAlkGWYzGza
28
+ h/3seA2bg1r5bbttFjD48f7RepfoAMxAqfiUWcukoukJeu7UY8jWmUIn9ut1oXct
29
+ Fh0YnueLFzzmppCCU+/SX5mc1y7mHYZHiU5n8qy1wJ6ljLWXVeprgJ96NdnmxuVU
30
+ dzPPSDTex/x7xBvHiaPc/uZSLc173N3qdY/Cd0B3/OflYeU2h5UpIHnmXrsONdMC
31
+ Xohy+Rrr2yT09MPYG+llpLHDnXmTnPsOZUSL5Q4c/iolodv4xJZKwLMZwrm2hQl9
32
+ 9Or9Os+qxY0zWxmWuAtTFrskLAMhckCPDEcqSZmW4CT1a/quC2Oh0y1GsXPcqtqt
33
+ hLRuwfTXGor6bg4CrU7GRbSqjvnBepct5lwZiZrOCnMEUpY+9Q8fwmG3o3B+wBsw
34
+ eBMcZq0d1tbtv1M1UXND9mOfhLZ31YvoSTPkrJiRpljUNgD0+ugelnr1/5X/9k8y
35
+ J9QOd3C5jpSShf/HMvpJnFuSYFm19cH9GrHjvw==
36
36
  -----END CERTIFICATE-----
37
- date: 2021-02-04 00:00:00.000000000 Z
37
+ date: 2021-08-06 00:00:00.000000000 Z
38
38
  dependencies:
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: request_store
metadata.gz.sig CHANGED
Binary file