mobility 1.0.5 → 1.1.2

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: 64a3453a8f28396a24b95987a4df6fb0fabfd3d90b03fccc47f6b82d72e77d8d
4
- data.tar.gz: 81ebec57acc6a48596d826716b37239549c01b68db59572d8bf6224b0d276831
3
+ metadata.gz: f5879d6ea43de5adf3be544ef11aaa634adabd6cad56609122450a1c648875f3
4
+ data.tar.gz: 7b0a1ed6187a0bb4aa75729c7e894c5673908e2443b50ba0da32f905ba4bf51f
5
5
  SHA512:
6
- metadata.gz: 63c3046ddce27b50708b73d78119b79b2e554bee7b92f8db843a3ea275acb91694da9c88c473e11c4ad07147bb7d9448229f44d7eb581f8d433313b7e6ecc34a
7
- data.tar.gz: 56ea4ab41a4984e54c5cb3ccf75fa13f42a4afbb3248463e65235fcdf879100bef6cdf34a29a482e5e790bb043bddf0dc6cb398a5fe24682a886882c6ace1bbb
6
+ metadata.gz: 860741ebf12f984401bac6b03726ac4b10a5c64befbd60a199130154768e6c2c34567009999487dcdaba49f41c12fd73f9fcb86441d9e7ad71b7d59adb4976a6
7
+ data.tar.gz: 27f2da6d8118a5b582035d721437f71520b2d4bcb81f8dba63c81f77b8c2d2e3badc6ec98349086e9c7fa651d62df38255c495cc76dccc0bb2bb6a988458e007
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # Mobility Changelog
2
2
 
3
- ### Unreleased
3
+ ## 1.1
4
+
5
+ ### 1.1.2
6
+ - Check whether class responds to mobility_attribute?
7
+ ([#515](https://github.com/shioyama/mobility/pull/515))
8
+
9
+ ### 1.1.1
10
+ - Updated signing key
11
+
12
+ ### 1.1.0
4
13
  - Remove `Mobility::Plugins::Attributes#each`
5
14
  ([#475](https://github.com/shioyama/mobility/pull/475))
6
15
  - Add public method `Mobility::Plugins::ActiveRecord::Query.build_query`
@@ -21,6 +30,14 @@
21
30
  v1.0](https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-v1.0)
22
31
  for more details on how to upgrade.
23
32
 
33
+ ### 1.0.7
34
+ - Require set before using Set
35
+ ([#503](https://github.com/shioyama/mobility/pull/503))
36
+
37
+ ### 1.0.6
38
+ - Merge options including defaults into backend options
39
+ ([#502](https://github.com/shioyama/mobility/pull/502))
40
+
24
41
  ### 1.0.5
25
42
  - Fix duping with AR Table backend, fixes
26
43
  [#490](https://github.com/shioyama/mobility/issues/490)
data/Gemfile.lock CHANGED
@@ -1,31 +1,37 @@
1
+ GIT
2
+ remote: https://github.com/rails/rails.git
3
+ revision: ac3910791d0294f6721e5a39e0063aa005535f10
4
+ branch: main
5
+ specs:
6
+ activemodel (7.0.0.alpha)
7
+ activesupport (= 7.0.0.alpha)
8
+ activerecord (7.0.0.alpha)
9
+ activemodel (= 7.0.0.alpha)
10
+ activesupport (= 7.0.0.alpha)
11
+ activesupport (7.0.0.alpha)
12
+ concurrent-ruby (~> 1.0, >= 1.0.2)
13
+ i18n (>= 1.6, < 2)
14
+ minitest (>= 5.1)
15
+ tzinfo (~> 2.0)
16
+ zeitwerk (~> 2.3)
17
+
1
18
  PATH
2
19
  remote: .
3
20
  specs:
4
- mobility (1.0.4)
21
+ mobility (1.1.1)
5
22
  i18n (>= 0.6.10, < 2)
6
23
  request_store (~> 1.0)
7
24
 
8
25
  GEM
9
26
  remote: https://rubygems.org/
10
27
  specs:
11
- activemodel (6.0.3.4)
12
- activesupport (= 6.0.3.4)
13
- activerecord (6.0.3.4)
14
- activemodel (= 6.0.3.4)
15
- activesupport (= 6.0.3.4)
16
- activesupport (6.0.3.4)
17
- concurrent-ruby (~> 1.0, >= 1.0.2)
18
- i18n (>= 0.7, < 2)
19
- minitest (~> 5.1)
20
- tzinfo (~> 1.1)
21
- zeitwerk (~> 2.2, >= 2.2.2)
22
- benchmark-ips (2.8.3)
28
+ benchmark-ips (2.8.4)
23
29
  byebug (11.1.3)
24
30
  coderay (1.1.3)
25
- concurrent-ruby (1.1.7)
26
- database_cleaner (1.8.5)
31
+ concurrent-ruby (1.1.8)
32
+ database_cleaner (1.99.0)
27
33
  diff-lcs (1.4.4)
28
- ffi (1.13.1)
34
+ ffi (1.15.0)
29
35
  formatador (0.2.5)
30
36
  guard (2.16.2)
31
37
  formatador (>= 0.2.4)
@@ -41,14 +47,14 @@ GEM
41
47
  guard (~> 2.1)
42
48
  guard-compat (~> 1.1)
43
49
  rspec (>= 2.99.0, < 4.0)
44
- i18n (1.8.5)
50
+ i18n (1.8.10)
45
51
  concurrent-ruby (~> 1.0)
46
- listen (3.2.1)
52
+ listen (3.5.1)
47
53
  rb-fsevent (~> 0.10, >= 0.10.3)
48
54
  rb-inotify (~> 0.9, >= 0.9.10)
49
55
  lumberjack (1.2.8)
50
56
  method_source (1.0.0)
51
- minitest (5.14.3)
57
+ minitest (5.14.4)
52
58
  nenv (0.3.0)
53
59
  notiffany (0.1.3)
54
60
  nenv (~> 0.1)
@@ -71,28 +77,28 @@ GEM
71
77
  rspec-core (~> 3.10.0)
72
78
  rspec-expectations (~> 3.10.0)
73
79
  rspec-mocks (~> 3.10.0)
74
- rspec-core (3.10.0)
80
+ rspec-core (3.10.1)
75
81
  rspec-support (~> 3.10.0)
76
- rspec-expectations (3.10.0)
82
+ rspec-expectations (3.10.1)
77
83
  diff-lcs (>= 1.2.0, < 2.0)
78
84
  rspec-support (~> 3.10.0)
79
- rspec-mocks (3.10.0)
85
+ rspec-mocks (3.10.2)
80
86
  diff-lcs (>= 1.2.0, < 2.0)
81
87
  rspec-support (~> 3.10.0)
82
- rspec-support (3.10.0)
88
+ rspec-support (3.10.2)
83
89
  shellany (0.0.1)
84
- thor (1.0.1)
85
- thread_safe (0.3.6)
86
- tzinfo (1.2.9)
87
- thread_safe (~> 0.1)
88
- yard (0.9.25)
90
+ thor (1.1.0)
91
+ tzinfo (2.0.4)
92
+ concurrent-ruby (~> 1.0)
93
+ yard (0.9.26)
89
94
  zeitwerk (2.4.2)
90
95
 
91
96
  PLATFORMS
92
97
  ruby
93
98
 
94
99
  DEPENDENCIES
95
- activerecord (~> 6.0.0)
100
+ activerecord!
101
+ activesupport!
96
102
  benchmark-ips
97
103
  database_cleaner (~> 1.5, >= 1.5.3)
98
104
  guard-rspec
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.5'
58
+ gem 'mobility', '~> 1.1.2'
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
@@ -83,8 +84,6 @@ module Mobility
83
84
  require "mobility/plugins"
84
85
  require "mobility/translations"
85
86
 
86
- # General error for version compatibility conflicts
87
- class VersionNotSupportedError < ArgumentError; end
88
87
  CALL_COMPILABLE_REGEXP = /\A[a-zA-Z_]\w*[!?]?\z/
89
88
  private_constant :CALL_COMPILABLE_REGEXP
90
89
 
@@ -201,6 +200,14 @@ module Mobility
201
200
  end
202
201
  end
203
202
 
203
+ # Check that a non-nil locale is valid. (Does not actually parse locale to
204
+ # check its format.)
205
+ # @raise [InvalidLocale] if locale is not a Symbol or not available
206
+ def validate_locale!(locale)
207
+ raise Mobility::InvalidLocale.new(locale) unless Symbol === locale
208
+ enforce_available_locales!(locale) if I18n.enforce_available_locales
209
+ end
210
+
204
211
  # Raises InvalidLocale exception if the locale passed in is present but not available.
205
212
  # @param [String,Symbol] locale
206
213
  # @raise [InvalidLocale] if locale is present but not available
@@ -217,7 +224,7 @@ module Mobility
217
224
  # simply default to +I18n.available_locales+, we may define many more
218
225
  # methods (in LocaleAccessors) than is really necessary.
219
226
  def available_locales
220
- if defined?(Rails) && Rails.application
227
+ if defined?(Rails) && Rails.respond_to?(:application) && Rails.application
221
228
  Rails.application.config.i18n.available_locales&.map(&:to_sym) || I18n.available_locales
222
229
  else
223
230
  I18n.available_locales
@@ -231,8 +238,8 @@ module Mobility
231
238
  end
232
239
 
233
240
  def set_locale(locale)
234
- locale = locale.to_sym if locale
235
- enforce_available_locales!(locale) if I18n.enforce_available_locales
241
+ locale = locale.to_sym if String === locale
242
+ validate_locale!(locale) if locale
236
243
  storage[:mobility_locale] = locale
237
244
  end
238
245
  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
@@ -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
 
@@ -1,4 +1,5 @@
1
1
  # frozen-string-literal: true
2
+ require "set"
2
3
  require "mobility/util"
3
4
  require "mobility/backends/sequel"
4
5
  require "mobility/backends/key_value"
@@ -31,14 +32,13 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
31
32
  options[:association_name] ||= :"#{options[:type]}_translations"
32
33
  options[:class_name] ||= const_get("#{type.capitalize}Translation")
33
34
  end
34
- options[:table_alias_affix] = "#{model_class}_%s_#{options[:association_name]}"
35
35
  rescue NameError
36
36
  raise ArgumentError, "You must define a Mobility::Sequel::#{type.capitalize}Translation class."
37
37
  end
38
38
  # @!endgroup
39
39
 
40
40
  def build_op(attr, locale)
41
- QualifiedIdentifier.new(table_alias(attr, locale), :value, locale, self, attr)
41
+ QualifiedIdentifier.new(table_alias(attr, locale), value_column, locale, self, attr)
42
42
  end
43
43
 
44
44
  # @param [Sequel::Dataset] dataset Dataset to prepare
@@ -57,10 +57,10 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
57
57
  dataset.join_table(join_type,
58
58
  class_name.table_name,
59
59
  {
60
- key: attr.to_s,
61
- locale: locale.to_s,
62
- translatable_type: model_class.name,
63
- 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]
64
64
  },
65
65
  table_alias: table_alias(attr, locale))
66
66
  end
@@ -126,27 +126,37 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
126
126
  backend = self
127
127
 
128
128
  setup do |attributes, options|
129
- association_name = options[:association_name]
130
- translations_class = options[:class_name]
131
-
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
+ #
132
142
  attrs_method_name = :"#{association_name}_attributes"
133
143
  association_attributes = (instance_variable_get(:"@#{attrs_method_name}") || []) + attributes
134
144
  instance_variable_set(:"@#{attrs_method_name}", association_attributes)
135
145
 
136
146
  one_to_many association_name,
137
- reciprocal: :translatable,
138
- key: :translatable_id,
147
+ reciprocal: belongs_to,
148
+ key: belongs_to_id,
139
149
  reciprocal_type: :one_to_many,
140
- conditions: { translatable_type: self.to_s, key: association_attributes },
141
- adder: proc { |translation| translation.update(translatable_id: pk, translatable_type: self.class.to_s) },
142
- remover: proc { |translation| translation.update(translatable_id: nil, translatable_type: nil) },
143
- clearer: proc { send(:"#{association_name}_dataset").update(translatable_id: nil, translatable_type: nil) },
144
- 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
145
155
 
146
156
  callback_methods = Module.new do
147
157
  define_method :before_save do
148
158
  super()
149
- 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)
150
160
  end
151
161
  define_method :after_save do
152
162
  super()
@@ -155,7 +165,17 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
155
165
  end
156
166
  include callback_methods
157
167
 
158
- 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
159
179
  include(mod = Module.new)
160
180
  backend.define_column_changes(mod, attributes)
161
181
  end
@@ -164,30 +184,19 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
164
184
  # @param [Symbol] locale
165
185
  # @return [Mobility::Backends::Sequel::KeyValue::TextTranslation,Mobility::Backends::Sequel::KeyValue::StringTranslation]
166
186
  def translation_for(locale, **)
167
- translation = model.send(association_name).find { |t| t.key == attribute && t.locale == locale.to_s }
168
- 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)
169
189
  translation
170
190
  end
171
191
 
172
192
  # Saves translation which have been built and which have non-blank values.
173
193
  def save_translations
174
194
  cache.each_value do |translation|
175
- next unless present?(translation.value)
195
+ next unless present?(translation.__send__ value_column)
176
196
  translation.id ? translation.save : model.send("add_#{singularize(association_name)}", translation)
177
197
  end
178
198
  end
179
199
 
180
- # Clean up *all* leftover translations of this model, only once.
181
- module DestroyKeyValueTranslations
182
- def after_destroy
183
- super
184
- [:string, :text].freeze.each do |type|
185
- Mobility::Backends::Sequel::KeyValue.const_get("#{type.capitalize}Translation").
186
- where(translatable_id: id, translatable_type: self.class.name).destroy
187
- end
188
- end
189
- end
190
-
191
200
  class CacheRequired < ::StandardError; end
192
201
 
193
202
  module Cache
@@ -211,8 +220,32 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
211
220
  end
212
221
  end
213
222
 
214
- module Translation
215
- 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
+
216
249
  base.class_eval do
217
250
  plugin :validation_helpers
218
251
 
@@ -220,16 +253,16 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
220
253
  #
221
254
  model = underscore(self.to_s)
222
255
  plural_model = pluralize(model)
223
- many_to_one :translatable,
256
+ many_to_one mod.belongs_to,
224
257
  reciprocal: plural_model.to_sym,
225
258
  reciprocal_type: :many_to_one,
226
259
  setter: (proc do |able_instance|
227
- self[:translatable_id] = (able_instance.pk if able_instance)
228
- 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)
229
262
  end),
230
263
  dataset: (proc do
231
- translatable_type = send :translatable_type
232
- translatable_id = send :translatable_id
264
+ translatable_type = send type_column
265
+ translatable_id = send id_column
233
266
  return if translatable_type.nil? || translatable_id.nil?
234
267
  klass = self.class.send(:constantize, translatable_type)
235
268
  klass.where(klass.primary_key => translatable_id)
@@ -237,29 +270,30 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
237
270
  eager_loader: (proc do |eo|
238
271
  id_map = {}
239
272
  eo[:rows].each do |model|
240
- model_able_type = model.send :translatable_type
241
- model_able_id = model.send :translatable_id
242
- 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
243
276
  ((id_map[model_able_type] ||= {})[model_able_id] ||= []) << model if !model_able_type.nil? && !model_able_id.nil?
244
277
  end
245
278
  id_map.each do |klass_name, id_map|
246
279
  klass = constantize(camelize(klass_name))
247
280
  klass.where(klass.primary_key=>id_map.keys).all do |related_obj|
248
281
  id_map[related_obj.pk].each do |model|
249
- model.associations[:translatable] = related_obj
282
+ model.associations[belongs_to] = related_obj
250
283
  end
251
284
  end
252
285
  end
253
286
  end)
254
287
 
255
- def validate
256
- super
257
- validates_presence [:locale, :key, :translatable_id, :translatable_type]
258
- 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]
259
292
  end
260
293
  end
261
294
  end
262
295
  end
296
+ Translation = Translatable.new(:key, :value, :translatable)
263
297
 
264
298
  class TextTranslation < ::Sequel::Model(:mobility_text_translations)
265
299
  include Translation
@@ -1,5 +1,6 @@
1
1
  # frozen-string-literal: true
2
2
  require "tsort"
3
+ require "set"
3
4
  require "mobility/util"
4
5
 
5
6
  module Mobility
@@ -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
@@ -83,7 +83,7 @@ Defines:
83
83
  @backend, @backend_options = options[:backend], options.dup
84
84
  when Array
85
85
  @backend, @backend_options = options[:backend]
86
- @backend_options = @backend_options.merge(original_options)
86
+ @backend_options = @backend_options.merge(options)
87
87
  when NilClass
88
88
  @backend = @backend_options = nil
89
89
  else
@@ -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 = 5
10
+ MINOR = 1
11
+ TINY = 2
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.5
4
+ version: 1.1.2
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-01-31 00:00:00.000000000 Z
37
+ date: 2021-04-26 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