mobility 0.1.11 → 0.1.12
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/Gemfile.lock +5 -5
- data/README.md +34 -23
- data/lib/mobility.rb +1 -0
- data/lib/mobility/attributes.rb +28 -34
- data/lib/mobility/backend.rb +1 -0
- data/lib/mobility/backend/active_model/dirty.rb +15 -3
- data/lib/mobility/backend/active_record/column.rb +1 -1
- data/lib/mobility/backend/active_record/key_value.rb +14 -2
- data/lib/mobility/backend/fallbacks.rb +2 -1
- data/lib/mobility/backend/presence.rb +30 -0
- data/lib/mobility/backend/sequel/key_value.rb +19 -3
- data/lib/mobility/fallthrough_accessors.rb +1 -1
- data/lib/mobility/instance_methods.rb +0 -21
- data/lib/mobility/locale_accessors.rb +55 -0
- data/lib/mobility/sequel/column_changes.rb +7 -7
- data/lib/mobility/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d5bbeab96e1792e6240d3f1854e302c5845689b
|
4
|
+
data.tar.gz: 0a821c40d9b1c3e6202a92e6194307fb0698c12c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cc59378dff919de4592e35b1a73e11ab808616ed1b6a9cdc84737e447a97a50d2503d348a41d3c8645f129a0f65554705a5696041c89950e5e7dd3b98b4f357
|
7
|
+
data.tar.gz: ed3e03d952e333bd04e4d366b0a9e6d523981e8270c1e5d7d36213e15806383ca3c6c0cd245e72b304420e725bcfbe400f4e3a28b32d64394a7ba29bf4f3004b
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,17 @@
|
|
2
2
|
|
3
3
|
## 0.1
|
4
4
|
|
5
|
+
### 0.1.12
|
6
|
+
* Extract presence filter into `Mobility::Backend::Presence` class
|
7
|
+
([7d654](https://github.com/shioyama/mobility/commit/7d65479c832ca154a45a548b64d27016486d34df),
|
8
|
+
[e42ee6](https://github.com/shioyama/mobility/commit/e42ee6123197594f3a8d694bff68c2ef4044562e))
|
9
|
+
* Get suffix methods from ActiveModel (for compatibility with Rails 4.2)
|
10
|
+
([9685d1](https://github.com/shioyama/mobility/commit/9685d182f285bddd2f5739a655f7c9e18998a5a1))
|
11
|
+
* Destroy all translations after model is destroyed (KeyValue backend)
|
12
|
+
([#15](https://github.com/shioyama/mobility/pull/15))
|
13
|
+
* Refactor to remove `mobility_get`, `mobility_set`. `mobility_present?` models
|
14
|
+
from model class ([#16](https://github.com/shioyama/mobility/pull/16))
|
15
|
+
|
5
16
|
### 0.1.11
|
6
17
|
* Add backend-specific translations generator (`rails generate
|
7
18
|
mobility:translations`)
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
mobility (0.1.
|
4
|
+
mobility (0.1.11)
|
5
5
|
i18n (>= 0.6.10)
|
6
6
|
request_store (~> 1.0)
|
7
7
|
|
@@ -29,9 +29,10 @@ GEM
|
|
29
29
|
guard-compat (~> 1.1)
|
30
30
|
rspec (>= 2.99.0, < 4.0)
|
31
31
|
i18n (0.8.1)
|
32
|
-
listen (3.
|
32
|
+
listen (3.1.5)
|
33
33
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
34
34
|
rb-inotify (~> 0.9, >= 0.9.7)
|
35
|
+
ruby_dep (~> 1.2)
|
35
36
|
lumberjack (1.0.11)
|
36
37
|
method_source (0.8.2)
|
37
38
|
mysql2 (0.3.21)
|
@@ -39,7 +40,7 @@ GEM
|
|
39
40
|
notiffany (0.1.1)
|
40
41
|
nenv (~> 0.1)
|
41
42
|
shellany (~> 0.0)
|
42
|
-
pg (0.
|
43
|
+
pg (0.20.0)
|
43
44
|
pry (0.10.4)
|
44
45
|
coderay (~> 1.1.0)
|
45
46
|
method_source (~> 0.8.1)
|
@@ -68,7 +69,7 @@ GEM
|
|
68
69
|
diff-lcs (>= 1.2.0, < 2.0)
|
69
70
|
rspec-support (~> 3.5.0)
|
70
71
|
rspec-support (3.5.0)
|
71
|
-
|
72
|
+
ruby_dep (1.5.0)
|
72
73
|
shellany (0.0.1)
|
73
74
|
slop (3.6.0)
|
74
75
|
sqlite3 (1.3.13)
|
@@ -89,7 +90,6 @@ DEPENDENCIES
|
|
89
90
|
rake (~> 10.0)
|
90
91
|
rspec (~> 3.0)
|
91
92
|
rspec-its (~> 1.2.0)
|
92
|
-
sequel (>= 4.0.0, < 5.0)
|
93
93
|
sqlite3
|
94
94
|
yard (~> 0.9.0)
|
95
95
|
|
data/README.md
CHANGED
@@ -37,7 +37,8 @@ platforms planned.
|
|
37
37
|
For a detailed introduction to Mobility, see [Translating with
|
38
38
|
Mobility](http://dejimata.com/2017/3/3/translating-with-mobility). See also the
|
39
39
|
[Roadmap](https://github.com/shioyama/mobility/wiki/Roadmap) for what's in the
|
40
|
-
works for future releases
|
40
|
+
works for future releases, and other pages of the [wiki][wiki] for more detail
|
41
|
+
on usage.
|
41
42
|
|
42
43
|
Installation
|
43
44
|
------------
|
@@ -45,7 +46,7 @@ Installation
|
|
45
46
|
Add this line to your application's Gemfile:
|
46
47
|
|
47
48
|
```ruby
|
48
|
-
gem 'mobility', '~> 0.1.
|
49
|
+
gem 'mobility', '~> 0.1.12'
|
49
50
|
```
|
50
51
|
|
51
52
|
To translate attributes on a model, include (or extend) `Mobility`, then call
|
@@ -97,10 +98,10 @@ You can include `Mobility` just like in ActiveRecord, or you can use the
|
|
97
98
|
`mobility` plugin, which does the same thing:
|
98
99
|
|
99
100
|
```ruby
|
100
|
-
class
|
101
|
+
class Word < ::Sequel::Model
|
101
102
|
plugin :mobility
|
102
|
-
translates :
|
103
|
-
translates :
|
103
|
+
translates :name, type: :string
|
104
|
+
translates :meaning, type: :text
|
104
105
|
end
|
105
106
|
```
|
106
107
|
|
@@ -108,7 +109,7 @@ Otherwise everything is (almost) identical to AR, with the exception that there
|
|
108
109
|
is no equivalent to a Rails generator (so you will need to create the migration
|
109
110
|
for any translation table(s) yourself, using Rails generators as a reference).
|
110
111
|
|
111
|
-
The models in examples below all inherit from `
|
112
|
+
The models in examples below all inherit from `ApplicationRecord`, but
|
112
113
|
everything works exactly the same if the parent class is `Sequel::Model`.
|
113
114
|
|
114
115
|
Usage
|
@@ -117,10 +118,12 @@ Usage
|
|
117
118
|
### <a name="quickstart"></a>Getting Started
|
118
119
|
|
119
120
|
Once the install generator has been run to generate translation tables, using
|
120
|
-
Mobility is as easy as adding a few lines to any class you want to translate
|
121
|
+
Mobility is as easy as adding a few lines to any class you want to translate.
|
122
|
+
Simply pass one or more attribute names to the `translates` method with a hash
|
123
|
+
of options, like this:
|
121
124
|
|
122
125
|
```ruby
|
123
|
-
class Word <
|
126
|
+
class Word < ApplicationRecord
|
124
127
|
include Mobility
|
125
128
|
translates :name, type: :string
|
126
129
|
translates :meaning, type: :text
|
@@ -221,7 +224,7 @@ accessors" in Mobility, and they can be defined by passing a `locale_accessors`
|
|
221
224
|
option when defining translated attributes on the model class:
|
222
225
|
|
223
226
|
```ruby
|
224
|
-
class Word <
|
227
|
+
class Word < ApplicationRecord
|
225
228
|
include Mobility
|
226
229
|
translates :name, type: :string, locale_accessors: [:en, :ja]
|
227
230
|
end
|
@@ -261,7 +264,7 @@ precedence if defined for a given locale.)
|
|
261
264
|
For example, if we define `Word` this way:
|
262
265
|
|
263
266
|
```ruby
|
264
|
-
class Word <
|
267
|
+
class Word < ApplicationRecord
|
265
268
|
include Mobility
|
266
269
|
translates :name, type: :string, fallthrough_accessors: true
|
267
270
|
end
|
@@ -366,7 +369,7 @@ pass a hash with fallbacks for each locale as an option when defining
|
|
366
369
|
translated attributes on a class:
|
367
370
|
|
368
371
|
```ruby
|
369
|
-
class Word <
|
372
|
+
class Word < ApplicationRecord
|
370
373
|
include Mobility
|
371
374
|
translates :name, type: :string, fallbacks: { de: :ja, fr: :ja }
|
372
375
|
translates :meaning, type: :text, fallbacks: { de: :ja, fr: :ja }
|
@@ -451,7 +454,7 @@ First, enable dirty tracking (note that this is a persisted AR model, although
|
|
451
454
|
dirty tracking is not specific to AR and works for non-persisted models as well):
|
452
455
|
|
453
456
|
```ruby
|
454
|
-
class Post <
|
457
|
+
class Post < ApplicationRecord
|
455
458
|
include Mobility
|
456
459
|
translates :title, type: :string, dirty: true
|
457
460
|
end
|
@@ -525,7 +528,7 @@ generally only be disabled when debugging; this can be done by passing `cache:
|
|
525
528
|
false` when defining an attribute, like this:
|
526
529
|
|
527
530
|
```ruby
|
528
|
-
class Word <
|
531
|
+
class Word < ApplicationRecord
|
529
532
|
include Mobility
|
530
533
|
translates :name, type: :string, cache: false
|
531
534
|
end
|
@@ -546,7 +549,7 @@ Mobility-specific query method overrides.
|
|
546
549
|
So assuming a model:
|
547
550
|
|
548
551
|
```ruby
|
549
|
-
class Post <
|
552
|
+
class Post < ApplicationRecord
|
550
553
|
include Mobility
|
551
554
|
translates :title, type: :string
|
552
555
|
translates :content, type: :text
|
@@ -590,7 +593,7 @@ If you would prefer to avoid the `i18n` scope everywhere, define it as a
|
|
590
593
|
default scope on your model:
|
591
594
|
|
592
595
|
```ruby
|
593
|
-
class Post <
|
596
|
+
class Post < ApplicationRecord
|
594
597
|
include Mobility
|
595
598
|
translates :title, type: :string
|
596
599
|
translates :content, type: :text
|
@@ -617,7 +620,7 @@ configuration, or you can set it explicitly when defining a translated
|
|
617
620
|
attribute, like this:
|
618
621
|
|
619
622
|
```ruby
|
620
|
-
class Word <
|
623
|
+
class Word < ApplicationRecord
|
621
624
|
translates :name, backend: :table
|
622
625
|
end
|
623
626
|
```
|
@@ -626,7 +629,8 @@ This would set the `name` attribute to use the `Table` backend (see below).
|
|
626
629
|
The `type` option (`type: :string` or `type: :text`) is missing here because
|
627
630
|
this is an option specific to the KeyValue backend (specifying which shared
|
628
631
|
table to store translations on). Backends have their own specific options; see
|
629
|
-
the API documentation for which options are available
|
632
|
+
the [Wiki][wiki] and [API documentation][api] for which options are available
|
633
|
+
for each.
|
630
634
|
|
631
635
|
Everything else described above (fallbacks, dirty tracking, locale accessors,
|
632
636
|
caching, querying, etc) is the same regardless of which backend you use.
|
@@ -648,12 +652,14 @@ rails generate mobility:translations post title:string content:text
|
|
648
652
|
|
649
653
|
This will generate the `post_translations` table with columns `title` and
|
650
654
|
`content`, and all other necessary columns and indices. For more details see
|
651
|
-
the
|
655
|
+
the [Table
|
656
|
+
Backend](https://github.com/shioyama/mobility/wiki/Table-Backend) page of the
|
657
|
+
wiki and API documentation on the [`Mobility::Backend::Table`
|
652
658
|
class](http://www.rubydoc.info/gems/mobility/Mobility/Backend/Table).
|
653
659
|
|
654
660
|
### Column Backend (like Traco)
|
655
661
|
|
656
|
-
The `Column` backend stores
|
662
|
+
The `Column` backend stores translations as columns with locale suffixes on
|
657
663
|
the model table. For an attribute `title`, these would be of the form
|
658
664
|
`title_en`, `title_fr`, etc.
|
659
665
|
|
@@ -664,7 +670,9 @@ Use the `mobility:translations` generator to add columns for locales in
|
|
664
670
|
rails generate mobility:translations post title:string content:text
|
665
671
|
```
|
666
672
|
|
667
|
-
For more details, see the
|
673
|
+
For more details, see the [Column
|
674
|
+
Backend](https://github.com/shioyama/mobility/wiki/Column-Backend) page of the
|
675
|
+
wiki and API documentation on the [`Mobility::Backend::Column`
|
668
676
|
class](http://www.rubydoc.info/gems/mobility/Mobility/Backend/Column).
|
669
677
|
|
670
678
|
### PostgreSQL-specific Backends
|
@@ -672,7 +680,9 @@ class](http://www.rubydoc.info/gems/mobility/Mobility/Backend/Column).
|
|
672
680
|
Mobility also supports jsonb and Hstore storage options, if you are using
|
673
681
|
PostgreSQL as your database. To use this option, create column(s) on the model
|
674
682
|
table for each translated attribute, and set your backend to `:jsonb` or
|
675
|
-
`:hstore`. Other details are covered in the
|
683
|
+
`:hstore`. Other details are covered in the [Postgres
|
684
|
+
Backend](https://github.com/shioyama/mobility/wiki/Postgres-Backends) page of
|
685
|
+
the wiki and in the API documentation
|
676
686
|
([`Mobility::Backend::Jsonb`](http://www.rubydoc.info/gems/mobility/Mobility/Backend/Jsonb)
|
677
687
|
and
|
678
688
|
[`Mobility::Backend::Hstore`](http://www.rubydoc.info/gems/mobility/Mobility/Backend/Hstore)).
|
@@ -703,8 +713,9 @@ class MyClass
|
|
703
713
|
end
|
704
714
|
```
|
705
715
|
|
706
|
-
For details on how to define a backend class, see the [
|
707
|
-
|
716
|
+
For details on how to define a backend class, see the [Introduction to Mobility
|
717
|
+
Backends](https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-Backends)
|
718
|
+
page of the wiki and the [API documentation on the `Mobility::Backend`
|
708
719
|
module](http://www.rubydoc.info/gems/mobility/Mobility/Backend).
|
709
720
|
|
710
721
|
### Testing Backends
|
data/lib/mobility.rb
CHANGED
@@ -37,6 +37,7 @@ module Mobility
|
|
37
37
|
autoload :BackendResetter, "mobility/backend_resetter"
|
38
38
|
autoload :Configuration, "mobility/configuration"
|
39
39
|
autoload :FallthroughAccessors, "mobility/fallthrough_accessors"
|
40
|
+
autoload :LocaleAccessors, "mobility/locale_accessors"
|
40
41
|
autoload :InstanceMethods, "mobility/instance_methods"
|
41
42
|
autoload :Translates, "mobility/translates"
|
42
43
|
autoload :Wrapper, "mobility/wrapper"
|
data/lib/mobility/attributes.rb
CHANGED
@@ -115,16 +115,18 @@ with other backends.
|
|
115
115
|
# @param [Array<String>] attributes_ Attributes to define backend for
|
116
116
|
# @param [Hash] options_ Backend options hash
|
117
117
|
# @option options_ [Class] model_class Class of model
|
118
|
-
# @option options_ [Boolean, Array<Symbol>] locale_accessors Enable locale
|
119
|
-
# accessors or specify locales for which accessors should be defined on
|
120
|
-
# this model backend. Will default to +true+ if +dirty+ option is +true+.
|
121
118
|
# @option options_ [Boolean] cache (true) Enable cache for this model backend
|
122
|
-
# @option options_ [Boolean, Hash] fallbacks Enable fallbacks or specify
|
123
|
-
# fallbacks for this model backend
|
124
119
|
# @option options_ [Boolean] dirty Enable dirty tracking for this model
|
125
120
|
# backend
|
121
|
+
# @option options_ [Boolean, Hash] fallbacks Enable fallbacks or specify
|
122
|
+
# fallbacks for this model backend
|
126
123
|
# @option options_ [Boolean] fallthrough_accessors Enable fallthrough
|
127
124
|
# locale accessors for this model backend
|
125
|
+
# @option options_ [Boolean, Array<Symbol>] locale_accessors Enable locale
|
126
|
+
# accessors or specify locales for which accessors should be defined on
|
127
|
+
# this model backend. Will default to +true+ if +dirty+ option is +true+.
|
128
|
+
# @option options_ [Boolean] presence (true) Enable presence filter on
|
129
|
+
# reads and writes
|
128
130
|
# @raise [ArgumentError] if method is not reader, writer or accessor
|
129
131
|
def initialize(method, *attributes_, **options_)
|
130
132
|
raise ArgumentError, "method must be one of: reader, writer, accessor" unless %i[reader writer accessor].include?(method)
|
@@ -137,7 +139,7 @@ with other backends.
|
|
137
139
|
if (options[:dirty] && options[:fallthrough_accessors] != false)
|
138
140
|
options[:fallthrough_accessors] = true
|
139
141
|
end
|
140
|
-
include FallthroughAccessors.new(attributes) if options[:fallthrough_accessors]
|
142
|
+
include FallthroughAccessors.new(*attributes) if options[:fallthrough_accessors]
|
141
143
|
|
142
144
|
@backend_class.configure!(options) if @backend_class.respond_to?(:configure!)
|
143
145
|
|
@@ -145,25 +147,12 @@ with other backends.
|
|
145
147
|
|
146
148
|
@accessor_locales = options[:locale_accessors]
|
147
149
|
@accessor_locales = Mobility.config.default_accessor_locales if @accessor_locales == true
|
150
|
+
include LocaleAccessors.new(*attributes, locales: @accessor_locales) if @accessor_locales
|
148
151
|
|
149
152
|
attributes.each do |attribute|
|
150
153
|
define_backend(attribute)
|
151
|
-
|
152
|
-
if %i[accessor
|
153
|
-
define_method attribute do |**options|
|
154
|
-
mobility_get(attribute, options)
|
155
|
-
end
|
156
|
-
|
157
|
-
define_method "#{attribute}?" do |**options|
|
158
|
-
mobility_present?(attribute, options)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
define_method "#{attribute}=" do |value, **options|
|
163
|
-
mobility_set(attribute, value, **options)
|
164
|
-
end if %i[accessor writer].include?(method)
|
165
|
-
|
166
|
-
define_locale_accessors(attribute, @accessor_locales) if @accessor_locales
|
154
|
+
define_reader(attribute) if %i[accessor reader].include?(method)
|
155
|
+
define_writer(attribute) if %i[accessor writer].include?(method)
|
167
156
|
end
|
168
157
|
end
|
169
158
|
|
@@ -188,6 +177,7 @@ with other backends.
|
|
188
177
|
backend_class.include(Backend::Cache) unless options[:cache] == false
|
189
178
|
backend_class.include(Backend::Dirty.for(options[:model_class])) if options[:dirty]
|
190
179
|
backend_class.include(Backend::Fallbacks) unless options[:fallbacks] == false
|
180
|
+
backend_class.include(Backend::Presence) unless options[:presence] == false
|
191
181
|
end
|
192
182
|
|
193
183
|
def define_backend(attribute)
|
@@ -198,18 +188,22 @@ with other backends.
|
|
198
188
|
end
|
199
189
|
end
|
200
190
|
|
201
|
-
def
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
191
|
+
def define_reader(attribute)
|
192
|
+
define_method attribute do |locale: Mobility.locale, **options|
|
193
|
+
Mobility.enforce_available_locales!(locale)
|
194
|
+
mobility_backend_for(attribute).read(locale.to_sym, options)
|
195
|
+
end
|
196
|
+
|
197
|
+
define_method "#{attribute}?" do |locale: Mobility.locale, **options|
|
198
|
+
Mobility.enforce_available_locales!(locale)
|
199
|
+
mobility_backend_for(attribute).read(locale.to_sym, options).present?
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def define_writer(attribute)
|
204
|
+
define_method "#{attribute}=" do |value, locale: Mobility.locale, **options|
|
205
|
+
Mobility.enforce_available_locales!(locale)
|
206
|
+
mobility_backend_for(attribute).write(locale.to_sym, value, options)
|
213
207
|
end
|
214
208
|
end
|
215
209
|
|
data/lib/mobility/backend.rb
CHANGED
@@ -60,6 +60,7 @@ On top of this, a backend will normally:
|
|
60
60
|
autoload :KeyValue, 'mobility/backend/key_value'
|
61
61
|
autoload :Null, 'mobility/backend/null'
|
62
62
|
autoload :OrmDelegator, 'mobility/backend/orm_delegator'
|
63
|
+
autoload :Presence, 'mobility/backend/presence'
|
63
64
|
autoload :Sequel, 'mobility/backend/sequel'
|
64
65
|
autoload :Serialized, 'mobility/backend/serialized'
|
65
66
|
autoload :Table, 'mobility/backend/table'
|
@@ -47,11 +47,11 @@ value of the translated attribute if passed to it.
|
|
47
47
|
def setup_model(model_class, attributes, **options)
|
48
48
|
super
|
49
49
|
model_class.class_eval do
|
50
|
-
|
50
|
+
Mobility::Backend::ActiveModel::Dirty.method_suffixes.each do |suffix|
|
51
51
|
attributes.each do |attribute|
|
52
52
|
class_eval <<-EOM, __FILE__, __LINE__ + 1
|
53
|
-
def #{attribute}
|
54
|
-
|
53
|
+
def #{attribute}#{suffix}
|
54
|
+
attribute#{suffix}(Mobility.normalize_locale_accessor("#{attribute}"))
|
55
55
|
end
|
56
56
|
EOM
|
57
57
|
end
|
@@ -80,6 +80,18 @@ value of the translated attribute if passed to it.
|
|
80
80
|
model_class.include restore_methods
|
81
81
|
end
|
82
82
|
end
|
83
|
+
|
84
|
+
# Get method suffixes. Creating an object just to get the list of
|
85
|
+
# suffixes is not very efficient, but the most reliable way given that
|
86
|
+
# they change from Rails version to version.
|
87
|
+
def self.method_suffixes
|
88
|
+
@method_suffixes ||=
|
89
|
+
begin
|
90
|
+
Class.new do
|
91
|
+
include ::ActiveModel::Dirty
|
92
|
+
end.attribute_method_matchers.map { |m| m.suffix }
|
93
|
+
end.select { |m| m =~ /\A_/ }
|
94
|
+
end
|
83
95
|
end
|
84
96
|
end
|
85
97
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
1
3
|
module Mobility
|
2
4
|
module Backend
|
3
5
|
=begin
|
@@ -54,7 +56,7 @@ Implements the {Mobility::Backend::KeyValue} backend for ActiveRecord models.
|
|
54
56
|
def self.configure!(options)
|
55
57
|
super
|
56
58
|
type = options[:type]
|
57
|
-
options[:class_name] ||= Mobility::ActiveRecord.const_get("#{type.capitalize}Translation")
|
59
|
+
options[:class_name] ||= Mobility::ActiveRecord.const_get("#{type.capitalize}Translation".freeze)
|
58
60
|
options[:class_name] = options[:class_name].constantize if options[:class_name].is_a?(String)
|
59
61
|
options[:association_name] ||= options[:class_name].table_name.to_sym
|
60
62
|
%i[type association_name].each { |key| options[key] = options[key].to_sym }
|
@@ -77,7 +79,6 @@ Implements the {Mobility::Backend::KeyValue} backend for ActiveRecord models.
|
|
77
79
|
has_many association_name, ->{ where key: association_attributes },
|
78
80
|
as: :translatable,
|
79
81
|
class_name: translations_class,
|
80
|
-
dependent: :destroy,
|
81
82
|
inverse_of: :translatable,
|
82
83
|
autosave: true
|
83
84
|
before_save do
|
@@ -85,6 +86,7 @@ Implements the {Mobility::Backend::KeyValue} backend for ActiveRecord models.
|
|
85
86
|
send(association_name).destroy(translation)
|
86
87
|
end
|
87
88
|
end
|
89
|
+
after_destroy :mobility_destroy_key_value_translations
|
88
90
|
|
89
91
|
mod = Module.new do
|
90
92
|
define_method :i18n do
|
@@ -92,6 +94,16 @@ Implements the {Mobility::Backend::KeyValue} backend for ActiveRecord models.
|
|
92
94
|
end
|
93
95
|
end
|
94
96
|
extend mod
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# Clean up *all* leftover translations of this model, only once.
|
101
|
+
def mobility_destroy_key_value_translations
|
102
|
+
[:string, :text].freeze.each do |type|
|
103
|
+
Mobility::ActiveRecord.const_get("#{type.capitalize}Translation".freeze).
|
104
|
+
where(translatable: self).destroy_all
|
105
|
+
end
|
106
|
+
end unless private_instance_methods(false).include?(:mobility_destroy_key_value_translations)
|
95
107
|
end
|
96
108
|
|
97
109
|
# @!group Cache Methods
|
@@ -95,11 +95,12 @@ locale was +nil+.
|
|
95
95
|
# @param [Boolean,Symbol,Array] fallback
|
96
96
|
# +false+ to disable fallbacks on lookup, or a locale or array of
|
97
97
|
# locales to set fallback(s) for this lookup.
|
98
|
-
def read(locale,
|
98
|
+
def read(locale, **options)
|
99
99
|
if !options[:fallbacks].nil?
|
100
100
|
warn "You passed an option with key 'fallbacks', which will be
|
101
101
|
ignored. Did you mean 'fallback'?"
|
102
102
|
end
|
103
|
+
fallback = options.delete(:fallback)
|
103
104
|
return super if fallback == false || (fallback.nil? && fallbacks.nil?)
|
104
105
|
(fallback ? [locale, *fallback] : fallbacks[locale]).detect do |fallback_locale|
|
105
106
|
value = super(fallback_locale, **options)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Mobility
|
2
|
+
module Backend
|
3
|
+
=begin
|
4
|
+
|
5
|
+
Applies presence filter to values fetched from backend and to values set on
|
6
|
+
backend. Included by default, but can be disabled with presence: false option.
|
7
|
+
|
8
|
+
=end
|
9
|
+
module Presence
|
10
|
+
# @group Backend Accessors
|
11
|
+
# @!macro backend_reader
|
12
|
+
# @param [Boolean] presence
|
13
|
+
# *false* to disable presence filter.
|
14
|
+
def read(locale, **options)
|
15
|
+
return super if options.delete(:presence) == false
|
16
|
+
value = super
|
17
|
+
value == false ? value : value.presence
|
18
|
+
end
|
19
|
+
|
20
|
+
# @group Backend Accessors
|
21
|
+
# @!macro backend_writer
|
22
|
+
# @param [Boolean] presence
|
23
|
+
# *false* to disable presence filter.
|
24
|
+
def write(locale, value, **options)
|
25
|
+
return super if options.delete(:presence) == false
|
26
|
+
super(locale, value == false ? value : value.presence, **options)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
1
3
|
module Mobility
|
2
4
|
module Backend
|
3
5
|
=begin
|
@@ -52,7 +54,7 @@ Implements the {Mobility::Backend::KeyValue} backend for Sequel models.
|
|
52
54
|
super
|
53
55
|
raise CacheRequired, "Cache required for Sequel::KeyValue backend" if options[:cache] == false
|
54
56
|
type = options[:type]
|
55
|
-
options[:class_name] ||= Mobility::Sequel.const_get("#{type.capitalize}Translation")
|
57
|
+
options[:class_name] ||= Mobility::Sequel.const_get("#{type.capitalize}Translation".freeze)
|
56
58
|
options[:class_name] = options[:class_name].constantize if options[:class_name].is_a?(String)
|
57
59
|
options[:association_name] ||= options[:class_name].table_name.to_sym
|
58
60
|
%i[type association_name].each { |key| options[key] = options[key].to_sym }
|
@@ -77,8 +79,6 @@ options[:class_name] ||= Mobility::Sequel.const_get("#{type.capitalize}Translati
|
|
77
79
|
clearer: proc { send(:"#{association_name}_dataset").update(translatable_id: nil, translatable_type: nil) },
|
78
80
|
class: translations_class
|
79
81
|
|
80
|
-
plugin :association_dependencies, association_name => :destroy
|
81
|
-
|
82
82
|
callback_methods = Module.new do
|
83
83
|
define_method :before_save do
|
84
84
|
super()
|
@@ -99,6 +99,22 @@ options[:class_name] ||= Mobility::Sequel.const_get("#{type.capitalize}Translati
|
|
99
99
|
extend extension
|
100
100
|
|
101
101
|
include Mobility::Sequel::ColumnChanges.new(attributes)
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
# Clean up *all* leftover translations of this model, only once.
|
106
|
+
def self.mobility_key_value_callbacks_module
|
107
|
+
@mobility_key_value_destroy_callbacks_module ||= Module.new do
|
108
|
+
def after_destroy
|
109
|
+
super
|
110
|
+
[:string, :text].freeze.each do |type|
|
111
|
+
Mobility::Sequel.const_get("#{type.capitalize}Translation".freeze).
|
112
|
+
where(translatable_id: id, translatable_type: self.class.name).destroy
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end unless respond_to?(:mobility_key_value_callbacks_module, true)
|
117
|
+
include mobility_key_value_callbacks_module
|
102
118
|
end
|
103
119
|
|
104
120
|
# @!group Cache Methods
|
@@ -34,7 +34,7 @@ model class is generated.
|
|
34
34
|
|
35
35
|
=end
|
36
36
|
class FallthroughAccessors < Module
|
37
|
-
# @param [
|
37
|
+
# @param [String] One or more attributes
|
38
38
|
def initialize(*attributes)
|
39
39
|
method_name_regex = /\A(#{attributes.join('|'.freeze)})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
|
40
40
|
|
@@ -11,26 +11,5 @@ Instance methods attached to all model classes when model includes or extends
|
|
11
11
|
def mobility_backend_for(attribute)
|
12
12
|
send(Backend.method_name(attribute))
|
13
13
|
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def mobility_get(*args)
|
18
|
-
value = mobility_read(*args)
|
19
|
-
value == false ? value : value.presence
|
20
|
-
end
|
21
|
-
|
22
|
-
def mobility_present?(*args)
|
23
|
-
mobility_read(*args).present?
|
24
|
-
end
|
25
|
-
|
26
|
-
def mobility_set(attribute, value, locale: Mobility.locale, **options)
|
27
|
-
Mobility.enforce_available_locales!(locale)
|
28
|
-
mobility_backend_for(attribute).write(locale.to_sym, value == false ? value : value.presence, **options)
|
29
|
-
end
|
30
|
-
|
31
|
-
def mobility_read(attribute, locale: Mobility.locale, **options)
|
32
|
-
Mobility.enforce_available_locales!(locale)
|
33
|
-
mobility_backend_for(attribute).read(locale.to_sym, options)
|
34
|
-
end
|
35
14
|
end
|
36
15
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Mobility
|
4
|
+
=begin
|
5
|
+
|
6
|
+
Defines methods for a set of locales to access translated attributes in those
|
7
|
+
locales directly with a method call, using a suffix including the locale:
|
8
|
+
|
9
|
+
article.title_pt_br
|
10
|
+
|
11
|
+
If no locales are passed as an option to the initializer,
|
12
|
+
+I18n.available_locales+ will be used by default.
|
13
|
+
|
14
|
+
@example
|
15
|
+
class Post
|
16
|
+
def title
|
17
|
+
"title in #{Mobility.locale}"
|
18
|
+
end
|
19
|
+
include Mobility::LocaleAccessors.new("title", locales: [:en, :fr])
|
20
|
+
end
|
21
|
+
|
22
|
+
Mobility.locale = :en
|
23
|
+
post = Post.new
|
24
|
+
post.title
|
25
|
+
#=> "title in en"
|
26
|
+
post.title_fr
|
27
|
+
#=> "title in fr"
|
28
|
+
|
29
|
+
=end
|
30
|
+
class LocaleAccessors < Module
|
31
|
+
# @param [String] One or more attributes
|
32
|
+
# @param [Array<Symbol>] Locales
|
33
|
+
def initialize(*attributes, locales: I18n.available_locales)
|
34
|
+
warning_message = "locale passed as option to locale accessor will be ignored".freeze
|
35
|
+
|
36
|
+
attributes.each do |attribute|
|
37
|
+
locales.each do |locale|
|
38
|
+
normalized_locale = Mobility.normalize_locale(locale)
|
39
|
+
define_method "#{attribute}_#{normalized_locale}" do |**options|
|
40
|
+
warn warning_message if options.delete(:locale)
|
41
|
+
Mobility.with_locale(locale) { send(attribute, options) }
|
42
|
+
end
|
43
|
+
define_method "#{attribute}_#{normalized_locale}?" do |**options|
|
44
|
+
warn warning_message if options.delete(:locale)
|
45
|
+
Mobility.with_locale(locale) { send("#{attribute}?", options) }
|
46
|
+
end
|
47
|
+
define_method "#{attribute}_#{normalized_locale}=" do |value, **options|
|
48
|
+
warn warning_message if options.delete(:locale)
|
49
|
+
Mobility.with_locale(locale) { send("#{attribute}=", value, options) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -11,18 +11,18 @@ is called.
|
|
11
11
|
def initialize(attributes)
|
12
12
|
@attributes = attributes
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
attributes.each do |attribute|
|
15
|
+
define_method "#{attribute}=" do |value, **options|
|
16
|
+
if send(attribute) != value
|
17
|
+
locale = options[:locale] || Mobility.locale
|
18
|
+
column = attribute.to_sym
|
19
|
+
column_with_locale = :"#{attribute}_#{Mobility.normalize_locale(locale)}"
|
19
20
|
@changed_columns << column_with_locale if !changed_columns.include?(column_with_locale)
|
20
21
|
@changed_columns << column if !changed_columns.include?(column)
|
21
22
|
end
|
23
|
+
super(value, **options)
|
22
24
|
end
|
23
|
-
super(attribute, value, locale: locale)
|
24
25
|
end
|
25
|
-
private :mobility_set
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
data/lib/mobility/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mobility
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Salzberg
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: request_store
|
@@ -186,6 +186,7 @@ files:
|
|
186
186
|
- lib/mobility/backend/key_value.rb
|
187
187
|
- lib/mobility/backend/null.rb
|
188
188
|
- lib/mobility/backend/orm_delegator.rb
|
189
|
+
- lib/mobility/backend/presence.rb
|
189
190
|
- lib/mobility/backend/sequel.rb
|
190
191
|
- lib/mobility/backend/sequel/column.rb
|
191
192
|
- lib/mobility/backend/sequel/column/query_methods.rb
|
@@ -210,6 +211,7 @@ files:
|
|
210
211
|
- lib/mobility/core_ext/string.rb
|
211
212
|
- lib/mobility/fallthrough_accessors.rb
|
212
213
|
- lib/mobility/instance_methods.rb
|
214
|
+
- lib/mobility/locale_accessors.rb
|
213
215
|
- lib/mobility/orm.rb
|
214
216
|
- lib/mobility/rails.rb
|
215
217
|
- lib/mobility/sequel.rb
|