mobility 1.0.0.alpha → 1.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +17 -1
  5. data/Gemfile.lock +15 -84
  6. data/README.md +3 -3
  7. data/lib/mobility.rb +6 -2
  8. data/lib/mobility/arel.rb +1 -1
  9. data/lib/mobility/backend.rb +8 -10
  10. data/lib/mobility/backends.rb +1 -1
  11. data/lib/mobility/backends/active_record/container.rb +2 -5
  12. data/lib/mobility/backends/active_record/hstore.rb +1 -1
  13. data/lib/mobility/backends/active_record/key_value.rb +1 -1
  14. data/lib/mobility/backends/active_record/serialized.rb +4 -0
  15. data/lib/mobility/backends/active_record/table.rb +1 -1
  16. data/lib/mobility/backends/container.rb +10 -2
  17. data/lib/mobility/backends/hash_valued.rb +4 -0
  18. data/lib/mobility/backends/jsonb.rb +1 -1
  19. data/lib/mobility/backends/key_value.rb +12 -15
  20. data/lib/mobility/backends/sequel.rb +2 -2
  21. data/lib/mobility/backends/sequel/container.rb +3 -5
  22. data/lib/mobility/backends/sequel/hstore.rb +1 -1
  23. data/lib/mobility/backends/sequel/json.rb +1 -0
  24. data/lib/mobility/backends/sequel/serialized.rb +4 -0
  25. data/lib/mobility/backends/table.rb +18 -23
  26. data/lib/mobility/pluggable.rb +21 -1
  27. data/lib/mobility/plugins.rb +2 -0
  28. data/lib/mobility/plugins/active_model/dirty.rb +11 -5
  29. data/lib/mobility/plugins/active_record/uniqueness_validation.rb +1 -1
  30. data/lib/mobility/plugins/backend.rb +38 -15
  31. data/lib/mobility/plugins/cache.rb +12 -5
  32. data/lib/mobility/plugins/default.rb +1 -1
  33. data/lib/mobility/plugins/fallbacks.rb +4 -4
  34. data/lib/mobility/plugins/fallthrough_accessors.rb +5 -6
  35. data/lib/mobility/plugins/locale_accessors.rb +2 -5
  36. data/lib/mobility/plugins/presence.rb +1 -1
  37. data/lib/mobility/plugins/reader.rb +2 -2
  38. data/lib/mobility/plugins/sequel/dirty.rb +1 -1
  39. data/lib/mobility/plugins/writer.rb +1 -1
  40. data/lib/mobility/version.rb +1 -1
  41. data/lib/rails/generators/mobility/templates/initializer.rb +2 -2
  42. metadata +2 -2
  43. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d2cfc984b6de27771cbdbe1e7cba1864134d7008a3c07a75a4f890ca0007a956
4
- data.tar.gz: b7ea3bc4122a9f536a58bd00dc18b8c47151168e39dc8b315bdc5ade77e6385b
3
+ metadata.gz: a27c475aac12e8c93750cd6b11b7b339912c95bb24ada1e579c8f87598359388
4
+ data.tar.gz: faf2187673842e059b204715e774b2ef22d0a98e6162d7014ef875236a0db192
5
5
  SHA512:
6
- metadata.gz: 745a3462d4ca4b9fe9a392a2c38e95a3a59626c8d560a7eaa5eb3650320c02a2b88797fe16bb5a203a3f0e42a401f632fcf620a5dcc0cc6e1f579dcb132a6a8e
7
- data.tar.gz: 54031f4838a210915a964b954289e435cd4280c663b24c5516b6050318c9a0551b9912d36c968a71c17ac9199d30f0edea40cd4441046f38d4085f5195c73606
6
+ metadata.gz: 51dfb02fb8624897834dbc9260eb7edc67f6120f2971de120f7084e59df0865a027eca3ccae435ba77604fa8086760a1c682b9879a4c625be71368fa21d3b2c7
7
+ data.tar.gz: 5133980f0433ba31d157ebda7e1a8028dc84aa8d8dc7ab6b0df94861c347e60f34b09665eb890341998080be5256bea566f7e0dea62f96f6c85fcfd931319969
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,6 +1,22 @@
1
1
  # Mobility Changelog
2
2
 
3
- ## 1.0.0.alpha (unreleased)
3
+ ## 1.0
4
+
5
+ 1.0 is a rewrite of many internals of the gem. Please see the [wiki page on v1.0](https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-v1.0) for more details on how to upgrade.
6
+
7
+ ## 1.0.0.beta1 (pre-release)
8
+
9
+ - Remove `Mobility::Backend#apply_plugin`
10
+ ([#454](https://github.com/shioyama/mobility/pull/454))
11
+ - Instance exec configure block if it takes no arguments
12
+ ([#456](https://github.com/shioyama/mobility/pull/456))
13
+ - Raise an exception if invalid options are passed to Translations initializer
14
+ ([#457](https://github.com/shioyama/mobility/pull/457/files))
15
+ - Fix Ruby 2.7 deprecation warnings
16
+ ([#460](https://github.com/shioyama/mobility/pull/460))
17
+
18
+ ## 1.0.0.alpha (pre-release)
19
+
4
20
  - Default fallbacks plugin to `true` when enabled
5
21
  ([#447](https://github.com/shioyama/mobility/pull/447))
6
22
  - Remove `Mobility::Backend.method_name`
@@ -1,38 +1,3 @@
1
- GIT
2
- remote: https://github.com/rails/rails.git
3
- revision: 0a608bd987fde4f9bc5bcf4bcebdb181d199cf4f
4
- specs:
5
- actionpack (6.1.0.alpha)
6
- actionview (= 6.1.0.alpha)
7
- activesupport (= 6.1.0.alpha)
8
- rack (~> 2.0, >= 2.0.9)
9
- rack-test (>= 0.6.3)
10
- rails-dom-testing (~> 2.0)
11
- rails-html-sanitizer (~> 1.0, >= 1.2.0)
12
- actionview (6.1.0.alpha)
13
- activesupport (= 6.1.0.alpha)
14
- builder (~> 3.1)
15
- erubi (~> 1.4)
16
- rails-dom-testing (~> 2.0)
17
- rails-html-sanitizer (~> 1.1, >= 1.2.0)
18
- activemodel (6.1.0.alpha)
19
- activesupport (= 6.1.0.alpha)
20
- activerecord (6.1.0.alpha)
21
- activemodel (= 6.1.0.alpha)
22
- activesupport (= 6.1.0.alpha)
23
- activesupport (6.1.0.alpha)
24
- concurrent-ruby (~> 1.0, >= 1.0.2)
25
- i18n (>= 1.6, < 2)
26
- minitest (>= 5.1)
27
- tzinfo (~> 2.0)
28
- zeitwerk (~> 2.3)
29
- railties (6.1.0.alpha)
30
- actionpack (= 6.1.0.alpha)
31
- activesupport (= 6.1.0.alpha)
32
- method_source
33
- rake (>= 0.8.7)
34
- thor (~> 1.0)
35
-
36
1
  PATH
37
2
  remote: .
38
3
  specs:
@@ -43,22 +8,15 @@ PATH
43
8
  GEM
44
9
  remote: https://rubygems.org/
45
10
  specs:
46
- actionmailer (0.6.1)
47
- actionpack (>= 0.9.5)
48
- benchmark-ips (2.8.2)
49
- builder (3.2.4)
11
+ allocation_stats (0.1.5)
12
+ benchmark-ips (2.8.3)
50
13
  byebug (11.1.3)
51
14
  coderay (1.1.3)
52
15
  concurrent-ruby (1.1.7)
53
- crass (1.0.6)
54
16
  database_cleaner (1.8.5)
55
17
  diff-lcs (1.4.4)
56
- erubi (1.9.0)
57
18
  ffi (1.13.1)
58
19
  formatador (0.2.5)
59
- generator_spec (0.9.4)
60
- activesupport (>= 3.0.0)
61
- railties (>= 3.0.0)
62
20
  guard (2.16.2)
63
21
  formatador (>= 0.2.4)
64
22
  listen (>= 2.7, < 4.0)
@@ -78,20 +36,12 @@ GEM
78
36
  listen (3.2.1)
79
37
  rb-fsevent (~> 0.10, >= 0.10.3)
80
38
  rb-inotify (~> 0.9, >= 0.9.10)
81
- loofah (2.7.0)
82
- crass (~> 1.0.2)
83
- nokogiri (>= 1.5.9)
84
- lumberjack (1.2.7)
39
+ lumberjack (1.2.8)
85
40
  method_source (1.0.0)
86
- mini_portile2 (2.4.0)
87
- minitest (5.14.2)
88
41
  nenv (0.3.0)
89
- nokogiri (1.10.10)
90
- mini_portile2 (~> 2.4.0)
91
42
  notiffany (0.1.3)
92
43
  nenv (~> 0.1)
93
44
  shellany (~> 0.0)
94
- pg (1.2.3)
95
45
  pry (0.13.1)
96
46
  coderay (~> 1.1)
97
47
  method_source (~> 1.0)
@@ -99,58 +49,39 @@ GEM
99
49
  byebug (~> 11.0)
100
50
  pry (~> 0.13.0)
101
51
  rack (2.2.3)
102
- rack-test (1.1.0)
103
- rack (>= 1.0, < 3)
104
- rails (0.9.5)
105
- actionmailer (>= 0.6.1)
106
- actionpack (>= 1.4.0)
107
- activerecord (>= 1.6.0)
108
- rake (>= 0.4.15)
109
- rails-dom-testing (2.0.3)
110
- activesupport (>= 4.2.0)
111
- nokogiri (>= 1.6)
112
- rails-html-sanitizer (1.3.0)
113
- loofah (~> 2.3)
114
52
  rake (12.3.3)
115
53
  rb-fsevent (0.10.4)
116
54
  rb-inotify (0.10.1)
117
55
  ffi (~> 1.0)
118
56
  request_store (1.5.0)
119
57
  rack (>= 1.4)
120
- rspec (3.9.0)
121
- rspec-core (~> 3.9.0)
122
- rspec-expectations (~> 3.9.0)
123
- rspec-mocks (~> 3.9.0)
124
- rspec-core (3.9.2)
125
- rspec-support (~> 3.9.3)
126
- rspec-expectations (3.9.2)
58
+ rspec (3.10.0)
59
+ rspec-core (~> 3.10.0)
60
+ rspec-expectations (~> 3.10.0)
61
+ rspec-mocks (~> 3.10.0)
62
+ rspec-core (3.10.0)
63
+ rspec-support (~> 3.10.0)
64
+ rspec-expectations (3.10.0)
127
65
  diff-lcs (>= 1.2.0, < 2.0)
128
- rspec-support (~> 3.9.0)
129
- rspec-mocks (3.9.1)
66
+ rspec-support (~> 3.10.0)
67
+ rspec-mocks (3.10.0)
130
68
  diff-lcs (>= 1.2.0, < 2.0)
131
- rspec-support (~> 3.9.0)
132
- rspec-support (3.9.3)
69
+ rspec-support (~> 3.10.0)
70
+ rspec-support (3.10.0)
133
71
  shellany (0.0.1)
134
72
  thor (1.0.1)
135
- tzinfo (2.0.2)
136
- concurrent-ruby (~> 1.0)
137
73
  yard (0.9.25)
138
- zeitwerk (2.4.0)
139
74
 
140
75
  PLATFORMS
141
76
  ruby
142
77
 
143
78
  DEPENDENCIES
144
- activerecord!
145
- activesupport!
79
+ allocation_stats
146
80
  benchmark-ips
147
81
  database_cleaner (~> 1.5, >= 1.5.3)
148
- generator_spec (~> 0.9.4)
149
82
  guard-rspec
150
83
  mobility!
151
- pg
152
84
  pry-byebug
153
- rails
154
85
  rake (~> 12, >= 12.2.1)
155
86
  rspec (~> 3.0)
156
87
  yard (~> 0.9.0)
data/README.md CHANGED
@@ -13,7 +13,7 @@ Mobility
13
13
  [wiki]: https://github.com/shioyama/mobility/wiki
14
14
 
15
15
  **This is the readme for the [`master`](https://github.com/shioyama/mobility)
16
- branch, which corresponds to v1.0.0.alpha, a pre-release version of Mobility.
16
+ branch, which corresponds to v1.0.0.beta, a pre-release version of Mobility.
17
17
  If you are using an earlier version (0.8.x or earlier), you probably want the
18
18
  readme on the [0-8-stable
19
19
  branch](https://github.com/shioyama/mobility/tree/0-8-stable).**
@@ -54,11 +54,11 @@ section of the wiki.
54
54
  Installation
55
55
  ------------
56
56
 
57
- To use the latest (unreleased) version of Mobility, add this line to your
57
+ To use the latest pre-version of Mobility 1.0, add this line to your
58
58
  application's Gemfile:
59
59
 
60
60
  ```ruby
61
- gem 'mobility', git: 'https://github.com/shioyama/mobility.git'
61
+ gem 'mobility', '~> 1.0.0.beta1'
62
62
  ```
63
63
 
64
64
  For the latest stable version of Mobility, see the readme on the
@@ -57,9 +57,13 @@ module Mobility
57
57
 
58
58
  # Configure Mobility
59
59
  # @yield [Mobility::Translations]
60
- def configure
60
+ def configure(&block)
61
61
  translates_with(Class.new(Translations)) unless @translations_class
62
- yield translations_class
62
+ if block.arity == 0
63
+ translations_class.instance_exec(&block)
64
+ else
65
+ yield translations_class
66
+ end
63
67
  end
64
68
  # @!endgroup
65
69
 
@@ -38,7 +38,7 @@ module Mobility
38
38
  attr_reader :locale
39
39
  attr_reader :attribute_name
40
40
 
41
- def initialize(relation, column_name, locale, backend_class, attribute_name: nil)
41
+ def initialize(relation, column_name, locale, backend_class, attribute_name = nil)
42
42
  @backend_class = backend_class
43
43
  @locale = locale
44
44
  @attribute_name = attribute_name || column_name
@@ -100,7 +100,7 @@ On top of this, a backend will normally:
100
100
  # @param [Symbol] locale Locale to read
101
101
  # @return [TrueClass,FalseClass] Whether translation is present for locale
102
102
  def present?(locale, options = {})
103
- Util.present?(read(locale, options))
103
+ Util.present?(read(locale, **options))
104
104
  end
105
105
 
106
106
  # @!method model_class
@@ -120,6 +120,13 @@ On top of this, a backend will normally:
120
120
 
121
121
  # Defines setup hooks for backend to customize model class.
122
122
  module ClassMethods
123
+ # Returns valid option keys for this backend. This is overriden in
124
+ # backends to define which keys are valid for each backend class.
125
+ # @return [Array]
126
+ def valid_keys
127
+ []
128
+ end
129
+
123
130
  # Assign block to be called on model class.
124
131
  # @yield [attribute_names, options]
125
132
  # @note When called multiple times, setup blocks will be appended
@@ -179,15 +186,6 @@ On top of this, a backend will normally:
179
186
  EOM
180
187
  end
181
188
 
182
- # Called from plugins to apply custom processing for this backend.
183
- # Name is the name of the plugin.
184
- # @param [Symbol] name Name of plugin
185
- # @return [Boolean] Whether the plugin was applied
186
- # @note This is currently only called by Plugins::Cache.
187
- def apply_plugin(_)
188
- false
189
- end
190
-
191
189
  # Show useful information about this backend class, if it has no name.
192
190
  # @return [String]
193
191
  def inspect
@@ -5,7 +5,7 @@ module Mobility
5
5
  class << self
6
6
  # @param [Symbol, Object] backend Name of backend to load.
7
7
  def load_backend(name)
8
- return name if Module === name
8
+ return name if Module === name || name.nil?
9
9
 
10
10
  unless (backend = @backends[name])
11
11
  require "mobility/backends/#{name}"
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require "mobility/backends/active_record"
3
+ require "mobility/backends/container"
3
4
  require "mobility/arel/nodes/pg_ops"
4
5
 
5
6
  module Mobility
@@ -11,11 +12,7 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
11
12
  =end
12
13
  class ActiveRecord::Container
13
14
  include ActiveRecord
14
-
15
- # @!method column_name
16
- # Returns name of json or jsonb column used to store translations
17
- # @return [Symbol] (:translations) Name of translations column
18
- option_reader :column_name
15
+ include Container
19
16
 
20
17
  # @!group Backend Accessors
21
18
  #
@@ -18,7 +18,7 @@ Implements the {Mobility::Backends::Hstore} backend for ActiveRecord models.
18
18
 
19
19
  # @!macro backend_writer
20
20
  def write(locale, value, options = {})
21
- super(locale, value && value.to_s, options)
21
+ super(locale, value && value.to_s, **options)
22
22
  end
23
23
  # @!endgroup
24
24
 
@@ -51,7 +51,7 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
51
51
  # translation table value column
52
52
  def build_node(attr, locale)
53
53
  aliased_table = class_name.arel_table.alias(table_alias(attr, locale))
54
- Arel::Attribute.new(aliased_table, :value, locale, self, attribute_name: attr.to_sym)
54
+ Arel::Attribute.new(aliased_table, :value, locale, self, attr.to_sym)
55
55
  end
56
56
 
57
57
  # Joins translations using either INNER/OUTER join appropriate to the query.
@@ -30,6 +30,10 @@ Implements {Mobility::Backends::Serialized} backend for ActiveRecord models.
30
30
  include ActiveRecord
31
31
  include HashValued
32
32
 
33
+ def self.valid_keys
34
+ super + [:format]
35
+ end
36
+
33
37
  # @!group Backend Configuration
34
38
  # @param (see Backends::Serialized.configure)
35
39
  # @option (see Backends::Serialized.configure)
@@ -283,7 +283,7 @@ columns to that table.
283
283
 
284
284
  # Returns translation for a given locale, or builds one if none is present.
285
285
  # @param [Symbol] locale
286
- def translation_for(locale, _)
286
+ def translation_for(locale, **)
287
287
  translation = translations.in_locale(locale)
288
288
  translation ||= translations.build(locale: locale)
289
289
  translation
@@ -19,8 +19,16 @@ stored).
19
19
 
20
20
  =end
21
21
  module Container
22
+ def self.included(backend_class)
23
+ backend_class.extend ClassMethods
24
+ backend_class.option_reader :column_name
25
+ end
26
+
27
+ module ClassMethods
28
+ def valid_keys
29
+ [:column_name]
30
+ end
31
+ end
22
32
  end
23
-
24
- register_backend(:container, Container)
25
33
  end
26
34
  end
@@ -36,6 +36,10 @@ Defines read and write methods that access the value at a key with value
36
36
  end
37
37
 
38
38
  module ClassMethods
39
+ def valid_keys
40
+ [:column_prefix, :column_suffix]
41
+ end
42
+
39
43
  def configure(options)
40
44
  options[:column_affix] = "#{options[:column_prefix]}%s#{options[:column_suffix]}"
41
45
  end
@@ -6,7 +6,7 @@ Stores translations as hash on Postgres jsonb column.
6
6
 
7
7
  ==Backend Options
8
8
 
9
- ===+prefix+ and +suffix+
9
+ ===+column_prefix+ and +column_suffix+
10
10
 
11
11
  Prefix and suffix to add to attribute name to generate jsonb column name.
12
12
 
@@ -54,13 +54,13 @@ other backends on model (otherwise one will overwrite the other).
54
54
 
55
55
  # @!group Backend Accessors
56
56
  # @!macro backend_reader
57
- def read(locale, options = {})
58
- translation_for(locale, options).value
57
+ def read(locale, **options)
58
+ translation_for(locale, **options).value
59
59
  end
60
60
 
61
61
  # @!macro backend_writer
62
- def write(locale, value, options = {})
63
- translation_for(locale, options).value = value
62
+ def write(locale, value, **options)
63
+ translation_for(locale, **options).value = value
64
64
  end
65
65
  # @!endgroup
66
66
 
@@ -83,6 +83,10 @@ other backends on model (otherwise one will overwrite the other).
83
83
  end
84
84
 
85
85
  module ClassMethods
86
+ def valid_keys
87
+ [:type, :association_name, :class_name]
88
+ end
89
+
86
90
  # @!group Backend Configuration
87
91
  # @option options [Symbol,String] type Column type to use
88
92
  # @option options [Symbol] association_name (:<type>_translations) Name
@@ -100,16 +104,9 @@ other backends on model (otherwise one will overwrite the other).
100
104
  end
101
105
  end
102
106
 
103
- # Apply custom processing for plugin
104
- # @param (see Backend::ClassMethods#apply_plugin)
105
- # @return (see Backend::ClassMethods#apply_plugin)
106
- def apply_plugin(name)
107
- if name == :cache
108
- include self::Cache
109
- true
110
- else
111
- super
112
- end
107
+ # Apply custom processing for cache plugin
108
+ def include_cache
109
+ include self::Cache
113
110
  end
114
111
 
115
112
  def table_alias(attr, locale)
@@ -123,7 +120,7 @@ other backends on model (otherwise one will overwrite the other).
123
120
  if cache.has_key?(locale)
124
121
  cache[locale]
125
122
  else
126
- cache[locale] = super(locale, options)
123
+ cache[locale] = super(locale, **options)
127
124
  end
128
125
  end
129
126
 
@@ -5,8 +5,8 @@ module Mobility
5
5
  module Backends
6
6
  module Sequel
7
7
  def self.included(backend_class)
8
- backend_class.include(Backend)
9
- backend_class.extend(ClassMethods)
8
+ backend_class.include Backend
9
+ backend_class.extend ClassMethods
10
10
  end
11
11
 
12
12
  module ClassMethods
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
- require "mobility/backends/sequel/json"
2
+ require "mobility/backends/sequel"
3
3
  require "mobility/backends/sequel/jsonb"
4
+ require "mobility/backends/container"
4
5
 
5
6
  module Mobility
6
7
  module Backends
@@ -11,10 +12,7 @@ Implements the {Mobility::Backends::Container} backend for Sequel models.
11
12
  =end
12
13
  class Sequel::Container
13
14
  include Sequel
14
-
15
- # @!method column_name
16
- # @return [Symbol] (:translations) Name of translations column
17
- option_reader :column_name
15
+ include Container
18
16
 
19
17
  # @!group Backend Accessors
20
18
  #
@@ -20,7 +20,7 @@ Implements the {Mobility::Backends::Hstore} backend for Sequel models.
20
20
  # @!group Backend Accessors
21
21
  # @!macro backend_writer
22
22
  def write(locale, value, options = {})
23
- super(locale, value && value.to_s, options)
23
+ super(locale, value && value.to_s, **options)
24
24
  end
25
25
  # @!endgroup
26
26
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'mobility/backends/sequel/pg_hash'
2
3
 
3
4
  Sequel.extension :pg_json, :pg_json_ops
@@ -36,6 +36,10 @@ Sequel serialization plugin.
36
36
  include Sequel
37
37
  include HashValued
38
38
 
39
+ def self.valid_keys
40
+ super + [:format]
41
+ end
42
+
39
43
  # @!group Backend Configuration
40
44
  # @param (see Backends::Serialized.configure)
41
45
  # @option (see Backends::Serialized.configure)
@@ -83,13 +83,13 @@ set.
83
83
 
84
84
  # @!group Backend Accessors
85
85
  # @!macro backend_reader
86
- def read(locale, options = {})
87
- translation_for(locale, options).send(attribute)
86
+ def read(locale, **options)
87
+ translation_for(locale, **options).send(attribute)
88
88
  end
89
89
 
90
90
  # @!macro backend_writer
91
- def write(locale, value, options = {})
92
- translation_for(locale, options).send("#{attribute}=", value)
91
+ def write(locale, value, **options)
92
+ translation_for(locale, **options).send("#{attribute}=", value)
93
93
  end
94
94
  # @!endgroup
95
95
 
@@ -104,25 +104,22 @@ set.
104
104
  model.send(association_name)
105
105
  end
106
106
 
107
- def self.included(backend)
108
- backend.extend ClassMethods
109
- backend.option_reader :association_name
110
- backend.option_reader :subclass_name
111
- backend.option_reader :foreign_key
112
- backend.option_reader :table_name
107
+ def self.included(backend_class)
108
+ backend_class.extend ClassMethods
109
+ backend_class.option_reader :association_name
110
+ backend_class.option_reader :subclass_name
111
+ backend_class.option_reader :foreign_key
112
+ backend_class.option_reader :table_name
113
113
  end
114
114
 
115
115
  module ClassMethods
116
- # Apply custom processing for plugin
117
- # @param (see Backend::Setup#apply_plugin)
118
- # @return (see Backend::Setup#apply_plugin)
119
- def apply_plugin(name)
120
- if name == :cache
121
- include self::Cache
122
- true
123
- else
124
- super
125
- end
116
+ def valid_keys
117
+ [:association_name, :subclass_name, :foreign_key, :table_name]
118
+ end
119
+
120
+ # Apply custom processing for cache plugin
121
+ def include_cache
122
+ include self::Cache
126
123
  end
127
124
 
128
125
  def table_alias(locale)
@@ -138,7 +135,7 @@ set.
138
135
  if cache.has_key?(locale)
139
136
  cache[locale]
140
137
  else
141
- cache[locale] = super(locale, options)
138
+ cache[locale] = super(locale, **options)
142
139
  end
143
140
  end
144
141
 
@@ -157,7 +154,5 @@ set.
157
154
  end
158
155
  end
159
156
  end
160
-
161
- register_backend(:table, Table)
162
157
  end
163
158
  end
@@ -17,6 +17,10 @@ Works with {Mobility::Plugin}. (Subclassed by {Mobility::Translations}.)
17
17
  Plugin.configure(self, defaults, &block)
18
18
  end
19
19
 
20
+ def included_plugins
21
+ included_modules.grep(Plugin)
22
+ end
23
+
20
24
  def defaults
21
25
  @defaults ||= {}
22
26
  end
@@ -28,9 +32,25 @@ Works with {Mobility::Plugin}. (Subclassed by {Mobility::Translations}.)
28
32
  end
29
33
 
30
34
  def initialize(*, **options)
31
- @options = self.class.defaults.merge(options)
35
+ initialize_options(options)
36
+ validate_options(@options)
32
37
  end
33
38
 
34
39
  attr_reader :options
40
+
41
+ private
42
+
43
+ def initialize_options(options)
44
+ @options = self.class.defaults.merge(options)
45
+ end
46
+
47
+ # This is overridden by backend plugin to exclude mixed-in backend options.
48
+ def validate_options(options)
49
+ plugin_keys = self.class.included_plugins.map { |p| Plugins.lookup_name(p) }
50
+ extra_keys = options.keys - plugin_keys
51
+ raise InvalidOptionKey, "No plugin configured for these keys: #{extra_keys.join(', ')}." unless extra_keys.empty?
52
+ end
53
+
54
+ class InvalidOptionKey < Error; end
35
55
  end
36
56
  end
@@ -14,6 +14,8 @@ declared in any order (dependencies will be resolved).
14
14
  class << self
15
15
  # @param [Symbol] name Name of plugin to load.
16
16
  def load_plugin(name)
17
+ return name if Module === name || name.nil?
18
+
17
19
  unless (plugin = @plugins[name])
18
20
  require "mobility/plugins/#{name}"
19
21
  raise LoadError, "plugin #{name} did not register itself correctly in Mobility::Plugins" unless (plugin = @plugins[name])
@@ -80,7 +80,12 @@ the ActiveRecord dirty plugin for more information.
80
80
  attribute_names.each do |name|
81
81
  dirty_handler_methods.each_pattern(name) do |method_name, attribute_method|
82
82
  define_method(method_name) do |*args|
83
- mutations_from_mobility.send(attribute_method, Dirty.append_locale(name), *args)
83
+ # for %s_changed?(from:, to:) pattern
84
+ if (kwargs = args.last).is_a?(Hash)
85
+ mutations_from_mobility.send(attribute_method, Dirty.append_locale(name), *args[0,-1], **kwargs)
86
+ else
87
+ mutations_from_mobility.send(attribute_method, Dirty.append_locale(name), *args)
88
+ end
84
89
  end
85
90
  end
86
91
 
@@ -130,11 +135,12 @@ the ActiveRecord dirty plugin for more information.
130
135
  public_patterns.each do |pattern|
131
136
  method_name = pattern % 'attribute'
132
137
 
138
+ kwargs = pattern == '%s_changed?' ? ', **kwargs' : ''
133
139
  module_eval <<-EOM, __FILE__, __LINE__ + 1
134
- def #{method_name}(attr_name, *rest)
140
+ def #{method_name}(attr_name, *rest#{kwargs})
135
141
  if (mutations_from_mobility.attribute_changed?(attr_name) ||
136
142
  mutations_from_mobility.attribute_previously_changed?(attr_name))
137
- mutations_from_mobility.send(#{method_name.inspect}, attr_name, *rest)
143
+ mutations_from_mobility.send(#{method_name.inspect}, attr_name, *rest#{kwargs})
138
144
  else
139
145
  super
140
146
  end
@@ -330,11 +336,11 @@ the ActiveRecord dirty plugin for more information.
330
336
  # @!group Backend Accessors
331
337
  # @!macro backend_writer
332
338
  # @param [Hash] options
333
- def write(locale, value, options = {})
339
+ def write(locale, value, **options)
334
340
  locale_accessor = Mobility.normalize_locale_accessor(attribute, locale)
335
341
  if model.changed_attributes.has_key?(locale_accessor) && model.changed_attributes[locale_accessor] == value
336
342
  mutations_from_mobility.restore_attribute!(locale_accessor)
337
- elsif read(locale, options.merge(locale: true)) != value
343
+ elsif read(locale, **options.merge(locale: true)) != value
338
344
  mutations_from_mobility.attribute_will_change!(locale_accessor)
339
345
  end
340
346
  super
@@ -35,7 +35,7 @@ module Mobility
35
35
  error_options = options.except(:case_sensitive, :scope, :conditions)
36
36
  error_options[:value] = value
37
37
 
38
- record.errors.add(attribute, :taken, error_options)
38
+ record.errors.add(attribute, :taken, **error_options)
39
39
  end
40
40
  else
41
41
  super
@@ -32,18 +32,12 @@ Defines:
32
32
 
33
33
  def initialize(*args, **original_options)
34
34
  super
35
- return unless Plugins::Backend.dependencies_satisfied?(self.class)
36
35
 
37
- case options[:backend]
38
- when String, Symbol, Class
39
- @backend, @backend_options = options[:backend], options
40
- when Array
41
- @backend, @backend_options = options[:backend]
42
- @backend_options = @backend_options.merge(original_options)
43
- when NilClass
44
- @backend = @backend_options = nil
45
- else
46
- raise ArgumentError, "backend must be either a backend name, a backend class, or a two-element array"
36
+ # Validate that the default backend from config has valid keys
37
+ if (default = self.class.defaults[:backend])
38
+ name, backend_options = default
39
+ extra_keys = backend_options.keys - backend.valid_keys
40
+ raise InvalidOptionKey, "These are not valid #{name} backend keys: #{extra_keys.join(', ')}." unless extra_keys.empty?
47
41
  end
48
42
 
49
43
  include InstanceMethods
@@ -58,8 +52,7 @@ Defines:
58
52
  klass.extend ClassMethods
59
53
 
60
54
  if backend
61
- @backend_class = load_backend(backend).
62
- build_subclass(klass, backend_options)
55
+ @backend_class = backend.build_subclass(klass, backend_options)
63
56
 
64
57
  backend_class.setup_model(klass, names)
65
58
 
@@ -83,10 +76,38 @@ Defines:
83
76
  raise e, "could not find a #{backend} backend. Did you forget to include an ORM plugin like active_record or sequel?"
84
77
  end
85
78
 
79
+ private
80
+
81
+ # Override to extract backend options from options hash.
82
+ def initialize_options(original_options)
83
+ super
84
+
85
+ case options[:backend]
86
+ when String, Symbol, Class
87
+ @backend, @backend_options = options[:backend], options
88
+ when Array
89
+ @backend, @backend_options = options[:backend]
90
+ @backend_options = @backend_options.merge(original_options)
91
+ when NilClass
92
+ @backend = @backend_options = nil
93
+ else
94
+ raise ArgumentError, "backend must be either a backend name, a backend class, or a two-element array"
95
+ end
96
+
97
+ @backend = load_backend(backend)
98
+ end
99
+
100
+ # Override default validation to exclude backend options, which may be
101
+ # mixed in with plugin options.
102
+ def validate_options(options)
103
+ return super unless backend
104
+ super(options.slice(*(options.keys - backend.valid_keys)))
105
+ end
106
+
86
107
  # Override default argument-handling in DSL to store kwargs passed along
87
108
  # with plugin name.
88
- def self.configure_default(defaults, key, *args, **kwargs)
89
- defaults[key] = [args[0], kwargs] unless args.empty?
109
+ def self.configure_default(defaults, key, backend = nil, backend_options = {})
110
+ defaults[key] = [backend, backend_options] if backend
90
111
  end
91
112
 
92
113
  module InstanceMethods
@@ -131,6 +152,8 @@ Defines:
131
152
  @mobility_backend_classes ||= {}
132
153
  end
133
154
  end
155
+
156
+ class InvalidOptionKey < Error; end
134
157
  end
135
158
 
136
159
  register_plugin(:backend, Backend)
@@ -7,8 +7,7 @@ module Mobility
7
7
  Caches values fetched from the backend so subsequent fetches can be performed
8
8
  more quickly. The cache stores cached values in a simple hash, which is not
9
9
  optimal for some storage strategies, so some backends (KeyValue, Table) use a
10
- custom module through the {Mobility::Backend::Setup#apply_plugin} hook. For
11
- details see the documentation for these backends.
10
+ custom module by defining a method, +include_cache+, on the backend class.
12
11
 
13
12
  The cache is reset when one of a set of events happens (saving, reloading,
14
13
  etc.). See {BackendResetter} for details.
@@ -28,12 +27,20 @@ Values are added to the cache in two ways:
28
27
  # Applies cache plugin to attributes.
29
28
  included_hook do |_, backend_class|
30
29
  if options[:cache]
31
- backend_class.include(BackendMethods) unless backend_class.apply_plugin(:cache)
30
+ if backend_class.respond_to?(:include_cache)
31
+ backend_class.include_cache
32
+ else
33
+ include_cache(backend_class)
34
+ end
32
35
  end
33
36
  end
34
37
 
35
38
  private
36
39
 
40
+ def include_cache(backend_class)
41
+ backend_class.include BackendMethods
42
+ end
43
+
37
44
  # Used in ORM cache plugins
38
45
  def define_cache_hooks(klass, *reset_methods)
39
46
  mod = self
@@ -55,11 +62,11 @@ Values are added to the cache in two ways:
55
62
  # @!method read(locale, value, options = {})
56
63
  # @option options [Boolean] cache *false* to disable cache.
57
64
  def read(locale, **options)
58
- return super(locale, options) if options.delete(:cache) == false
65
+ return super(locale, **options) if options.delete(:cache) == false
59
66
  if cache.has_key?(locale)
60
67
  cache[locale]
61
68
  else
62
- cache[locale] = super(locale, options)
69
+ cache[locale] = super(locale, **options)
63
70
  end
64
71
  end
65
72
 
@@ -90,7 +90,7 @@ The proc can accept zero to three arguments (see examples below)
90
90
  # *false* to disable presence filter.
91
91
  def read(locale, accessor_options = {})
92
92
  default = accessor_options.has_key?(:default) ? accessor_options.delete(:default) : options[:default]
93
- if (value = super(locale, accessor_options)).nil?
93
+ if (value = super(locale, **accessor_options)).nil?
94
94
  Default[default, locale: locale, accessor_options: accessor_options, model: model, attribute: attribute]
95
95
  else
96
96
  value
@@ -47,7 +47,7 @@ the current locale was +nil+.
47
47
  Mobility.locale = :ja
48
48
  post.title
49
49
  #=> "foo"
50
-
50
+
51
51
  post.title = "bar"
52
52
  post.title
53
53
  #=> "bar"
@@ -144,15 +144,15 @@ the current locale was +nil+.
144
144
 
145
145
  def define_read(fallbacks)
146
146
  define_method :read do |locale, fallback: true, **options|
147
- return super(locale, options) if !fallback || options[:locale]
147
+ return super(locale, **options) if !fallback || options[:locale]
148
148
 
149
149
  locales = fallback == true ? fallbacks[locale] : [locale, *fallback]
150
150
  locales.each do |fallback_locale|
151
- value = super(fallback_locale, options)
151
+ value = super(fallback_locale, **options)
152
152
  return value if Util.present?(value)
153
153
  end
154
154
 
155
- super(locale, options)
155
+ super(locale, **options)
156
156
  end
157
157
  end
158
158
 
@@ -24,14 +24,11 @@ model class is generated.
24
24
 
25
25
  default true
26
26
 
27
- requires :reader
28
- requires :writer
29
-
30
27
  # Apply fallthrough accessors plugin to attributes.
31
28
  # @param [Translations] translations
32
29
  # @param [Boolean] option
33
30
  initialize_hook do
34
- if options[:fallthrough_accessors] && options[:reader] && options[:writer]
31
+ if options[:fallthrough_accessors]
35
32
  define_fallthrough_accessors(names)
36
33
  end
37
34
  end
@@ -47,9 +44,11 @@ model class is generated.
47
44
  locale, suffix = $2.split('_')
48
45
  locale = "#{locale}-#{suffix.upcase}" if suffix
49
46
  if $4 == '=' # writer
50
- public_send(attribute_method, args[0], **(args[1] || {}), locale: locale)
47
+ kwargs = args[1].is_a?(Hash) ? args[1] : {}
48
+ public_send(attribute_method, args[0], **kwargs, locale: locale)
51
49
  else # reader
52
- public_send(attribute_method, **(args[0] || {}), locale: locale)
50
+ kwargs = args[0].is_a?(Hash) ? args[0] : {}
51
+ public_send(attribute_method, **kwargs, locale: locale)
53
52
  end
54
53
  else
55
54
  super(method_name, *args, &block)
@@ -19,9 +19,6 @@ available locales for a Rails application) will be used by default.
19
19
 
20
20
  default true
21
21
 
22
- requires :reader
23
- requires :writer
24
-
25
22
  # Apply locale accessors plugin to attributes.
26
23
  # @param [Translations] translations
27
24
  # @param [Boolean] option
@@ -30,8 +27,8 @@ available locales for a Rails application) will be used by default.
30
27
  locales = Mobility.available_locales if locales == true
31
28
  names.each do |name|
32
29
  locales.each do |locale|
33
- define_locale_reader(name, locale) if options[:reader]
34
- define_locale_writer(name, locale) if options[:writer]
30
+ define_locale_reader(name, locale)
31
+ define_locale_writer(name, locale)
35
32
  end
36
33
  end
37
34
  end
@@ -39,7 +39,7 @@ backend.
39
39
  if options.delete(:presence) == false
40
40
  super
41
41
  else
42
- super(locale, Presence[value], options)
42
+ super(locale, Presence[value], **options)
43
43
  end
44
44
  end
45
45
  # @!endgroup
@@ -19,13 +19,13 @@ Defines attribute reader that delegates to +Mobility::Backend#read+.
19
19
  class_eval <<-EOM, __FILE__, __LINE__ + 1
20
20
  def #{name}(locale: nil, **options)
21
21
  #{Reader.setup_source}
22
- mobility_backends[:#{name}].read(locale, options)
22
+ mobility_backends[:#{name}].read(locale, **options)
23
23
  end
24
24
  EOM
25
25
  class_eval <<-EOM, __FILE__, __LINE__ + 1
26
26
  def #{name}?(locale: nil, **options)
27
27
  #{Reader.setup_source}
28
- mobility_backends[:#{name}].present?(locale, options)
28
+ mobility_backends[:#{name}].present?(locale, **options)
29
29
  end
30
30
  EOM
31
31
  end
@@ -56,7 +56,7 @@ Automatically includes dirty plugin in model class when enabled.
56
56
  if model.column_changes.has_key?(locale_accessor) && model.initial_values[locale_accessor] == value
57
57
  super
58
58
  [model.changed_columns, model.initial_values].each { |h| h.delete(locale_accessor) }
59
- elsif read(locale, options.merge(fallback: false)) != value
59
+ elsif read(locale, **options.merge(fallback: false)) != value
60
60
  model.will_change_column(locale_accessor)
61
61
  super
62
62
  end
@@ -19,7 +19,7 @@ Defines attribute writer that delegates to +Mobility::Backend#write+.
19
19
  class_eval <<-EOM, __FILE__, __LINE__ + 1
20
20
  def #{name}=(value, locale: nil, **options)
21
21
  #{Writer.setup_source}
22
- mobility_backends[:#{name}].write(locale, value, options)
22
+ mobility_backends[:#{name}].write(locale, value, **options)
23
23
  end
24
24
  EOM
25
25
  end
@@ -9,7 +9,7 @@ module Mobility
9
9
  MAJOR = 1
10
10
  MINOR = 0
11
11
  TINY = 0
12
- PRE = "alpha"
12
+ PRE = "beta1"
13
13
 
14
14
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
15
15
  end
@@ -1,7 +1,7 @@
1
- Mobility.configure do |config|
1
+ Mobility.configure do
2
2
 
3
3
  # PLUGINS
4
- config.plugins do
4
+ plugins do
5
5
  # Backend
6
6
  #
7
7
  # Sets the default backend to use in models. This can be overridden in models
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.0.alpha
4
+ version: 1.0.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Salzberg
@@ -34,7 +34,7 @@ cert_chain:
34
34
  gSQml7TqcC6dZRsZRwYqzD9kUwdAJoCqno2CBUKs2l0yQAjFT36lRrVJznb7uWwa
35
35
  xpPFnsrtyaZW6Dty8TSG3qzmeGpmpIotA8x1VA==
36
36
  -----END CERTIFICATE-----
37
- date: 2020-10-25 00:00:00.000000000 Z
37
+ date: 2020-11-03 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