mobility 0.4.3 → 0.5.0
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
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile.lock +27 -27
- data/README.md +8 -8
- data/lib/mobility.rb +18 -5
- data/lib/mobility/{wrapper.rb → accumulator.rb} +2 -4
- data/lib/mobility/active_record.rb +1 -0
- data/lib/mobility/active_record/backend_resetter.rb +1 -0
- data/lib/mobility/active_record/string_translation.rb +1 -0
- data/lib/mobility/active_record/text_translation.rb +1 -0
- data/lib/mobility/adapter.rb +19 -0
- data/lib/mobility/attributes.rb +2 -1
- data/lib/mobility/backend.rb +1 -1
- data/lib/mobility/backend/orm_delegator.rb +5 -4
- data/lib/mobility/backend_resetter.rb +2 -0
- data/lib/mobility/backends/active_record/column.rb +1 -0
- data/lib/mobility/backends/active_record/column/query_methods.rb +1 -0
- data/lib/mobility/backends/active_record/container.rb +21 -4
- data/lib/mobility/backends/active_record/container/json_query_methods.rb +30 -0
- data/lib/mobility/backends/active_record/container/{query_methods.rb → jsonb_query_methods.rb} +4 -2
- data/lib/mobility/backends/active_record/json.rb +36 -0
- data/lib/mobility/backends/active_record/json/query_methods.rb +25 -0
- data/lib/mobility/backends/active_record/jsonb.rb +4 -4
- data/lib/mobility/backends/active_record/jsonb/query_methods.rb +1 -0
- data/lib/mobility/backends/active_record/key_value.rb +2 -2
- data/lib/mobility/backends/active_record/key_value/query_methods.rb +1 -0
- data/lib/mobility/backends/active_record/pg_hash.rb +1 -0
- data/lib/mobility/backends/active_record/pg_query_methods.rb +1 -1
- data/lib/mobility/backends/active_record/serialized.rb +1 -0
- data/lib/mobility/backends/active_record/serialized/query_methods.rb +1 -0
- data/lib/mobility/backends/active_record/table.rb +2 -2
- data/lib/mobility/backends/active_record/table/query_methods.rb +1 -0
- data/lib/mobility/backends/column.rb +2 -0
- data/lib/mobility/backends/json.rb +20 -0
- data/lib/mobility/backends/jsonb.rb +0 -1
- data/lib/mobility/backends/key_value.rb +1 -0
- data/lib/mobility/backends/sequel/column.rb +1 -0
- data/lib/mobility/backends/sequel/column/query_methods.rb +1 -0
- data/lib/mobility/backends/sequel/container.rb +19 -3
- data/lib/mobility/backends/sequel/container/json_query_methods.rb +34 -0
- data/lib/mobility/backends/sequel/container/{query_methods.rb → jsonb_query_methods.rb} +2 -1
- data/lib/mobility/backends/sequel/hstore/query_methods.rb +1 -0
- data/lib/mobility/backends/sequel/json.rb +36 -0
- data/lib/mobility/backends/sequel/json/query_methods.rb +27 -0
- data/lib/mobility/backends/sequel/jsonb/query_methods.rb +2 -1
- data/lib/mobility/backends/sequel/key_value.rb +3 -3
- data/lib/mobility/backends/sequel/key_value/query_methods.rb +1 -0
- data/lib/mobility/backends/sequel/pg_hash.rb +1 -0
- data/lib/mobility/backends/sequel/query_methods.rb +1 -0
- data/lib/mobility/backends/sequel/serialized.rb +1 -0
- data/lib/mobility/backends/sequel/serialized/query_methods.rb +1 -0
- data/lib/mobility/backends/sequel/table.rb +1 -0
- data/lib/mobility/backends/sequel/table/query_methods.rb +1 -0
- data/lib/mobility/backends/serialized.rb +1 -0
- data/lib/mobility/backends/table.rb +1 -0
- data/lib/mobility/configuration.rb +3 -5
- data/lib/mobility/fallbacks.rb +28 -0
- data/lib/mobility/plugins/active_model/dirty.rb +5 -5
- data/lib/mobility/plugins/active_record/dirty.rb +1 -1
- data/lib/mobility/plugins/cache.rb +1 -0
- data/lib/mobility/plugins/default.rb +2 -0
- data/lib/mobility/plugins/dirty.rb +1 -0
- data/lib/mobility/plugins/fallbacks.rb +3 -1
- data/lib/mobility/plugins/fallthrough_accessors.rb +4 -4
- data/lib/mobility/plugins/locale_accessors.rb +2 -2
- data/lib/mobility/plugins/presence.rb +1 -0
- data/lib/mobility/sequel/column_changes.rb +3 -1
- data/lib/mobility/sequel/hash_initializer.rb +2 -0
- data/lib/mobility/sequel/string_translation.rb +1 -0
- data/lib/mobility/sequel/text_translation.rb +1 -0
- data/lib/mobility/translates.rb +2 -0
- data/lib/mobility/util.rb +3 -1
- data/lib/mobility/version.rb +3 -1
- data/lib/rails/generators/mobility/active_record_migration_compatibility.rb +1 -0
- data/lib/rails/generators/mobility/backend_generators/base.rb +3 -3
- data/lib/rails/generators/mobility/generators.rb +1 -0
- data/lib/rails/generators/mobility/install_generator.rb +1 -0
- data/lib/rails/generators/mobility/templates/initializer.rb +75 -0
- data/lib/rails/generators/mobility/translations_generator.rb +3 -3
- metadata +14 -5
- metadata.gz.sig +0 -0
@@ -46,7 +46,7 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
|
|
46
46
|
super
|
47
47
|
raise CacheRequired, "Cache required for Sequel::KeyValue backend" if options[:cache] == false
|
48
48
|
type = options[:type]
|
49
|
-
options[:class_name] ||= Mobility::Sequel.const_get("#{type.capitalize}Translation"
|
49
|
+
options[:class_name] ||= Mobility::Sequel.const_get("#{type.capitalize}Translation")
|
50
50
|
options[:class_name] = options[:class_name].constantize if options[:class_name].is_a?(String)
|
51
51
|
options[:association_name] ||= :"#{options[:type]}_translations"
|
52
52
|
%i[type association_name].each { |key| options[key] = options[key].to_sym }
|
@@ -78,7 +78,7 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
|
|
78
78
|
end
|
79
79
|
define_method :after_save do
|
80
80
|
super()
|
81
|
-
attributes.each { |attribute|
|
81
|
+
attributes.each { |attribute| public_send(Backend.method_name(attribute)).save_translations }
|
82
82
|
end
|
83
83
|
end
|
84
84
|
include callback_methods
|
@@ -93,7 +93,7 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
|
|
93
93
|
def after_destroy
|
94
94
|
super
|
95
95
|
[:string, :text].freeze.each do |type|
|
96
|
-
Mobility::Sequel.const_get("#{type.capitalize}Translation"
|
96
|
+
Mobility::Sequel.const_get("#{type.capitalize}Translation").
|
97
97
|
where(translatable_id: id, translatable_type: self.class.name).destroy
|
98
98
|
end
|
99
99
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Mobility
|
2
4
|
=begin
|
3
5
|
|
@@ -101,15 +103,11 @@ default_fallbacks= will be removed in the next major version of Mobility.
|
|
101
103
|
def initialize
|
102
104
|
@accessor_method = :translates
|
103
105
|
@query_method = :i18n
|
104
|
-
@fallbacks_generator = lambda { |fallbacks|
|
106
|
+
@fallbacks_generator = lambda { |fallbacks| Mobility::Fallbacks.build(fallbacks) }
|
105
107
|
@default_accessor_locales = lambda { I18n.available_locales }
|
106
108
|
@default_options = Options[{
|
107
109
|
cache: true,
|
108
|
-
dirty: false,
|
109
|
-
fallbacks: nil,
|
110
110
|
presence: true,
|
111
|
-
default: nil,
|
112
|
-
attribute_methods: false
|
113
111
|
}]
|
114
112
|
@plugins = %i[
|
115
113
|
cache
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Mobility
|
2
|
+
=begin
|
3
|
+
|
4
|
+
Subclasses +I18n::Locale::Fallbacks+ such that instances of this class
|
5
|
+
fall through to fallbacks defined in +I18n.fallbacks+. This allows models to
|
6
|
+
customize fallbacks while still falling through to any fallbacks defined
|
7
|
+
globally.
|
8
|
+
|
9
|
+
=end
|
10
|
+
class Fallbacks < ::I18n::Locale::Fallbacks
|
11
|
+
# @param [Symbol] locale
|
12
|
+
# @return [Array] locales
|
13
|
+
def [](locale)
|
14
|
+
super | I18n.fallbacks[locale]
|
15
|
+
end
|
16
|
+
|
17
|
+
# For this set of fallbacks, return a new fallbacks hash.
|
18
|
+
# @param [Hash] fallbacks
|
19
|
+
# @return [I18n::Locale::Fallbacks,Mobility::Fallbacks] fallbacks hash
|
20
|
+
def self.build(fallbacks)
|
21
|
+
if I18n.respond_to?(:fallbacks)
|
22
|
+
new(fallbacks)
|
23
|
+
else
|
24
|
+
I18n::Locale::Fallbacks.new(fallbacks)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -45,21 +45,21 @@ value of the translated attribute if passed to it.
|
|
45
45
|
def initialize(*attribute_names)
|
46
46
|
attribute_names.each do |name|
|
47
47
|
method_suffixes.each do |suffix|
|
48
|
-
define_method "#{name}#{suffix}"
|
49
|
-
__send__("attribute#{suffix}"
|
48
|
+
define_method "#{name}#{suffix}" do
|
49
|
+
__send__("attribute#{suffix}", Mobility.normalize_locale_accessor(name))
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
define_method "restore_#{name}!"
|
53
|
+
define_method "restore_#{name}!" do
|
54
54
|
locale_accessor = Mobility.normalize_locale_accessor(name)
|
55
55
|
if attribute_changed?(locale_accessor)
|
56
|
-
__send__("#{name}="
|
56
|
+
__send__("#{name}=", changed_attributes[locale_accessor])
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
61
|
define_method :restore_attribute! do |attr|
|
62
|
-
attribute_names.include?(attr.to_s) ? send("restore_#{attr}!"
|
62
|
+
attribute_names.include?(attr.to_s) ? send("restore_#{attr}!") : super(attr)
|
63
63
|
end
|
64
64
|
private :restore_attribute!
|
65
65
|
end
|
@@ -46,7 +46,7 @@ AR::Dirty plugin adds support for the following persistence-specific methods
|
|
46
46
|
|
47
47
|
if ::ActiveRecord::VERSION::MAJOR == 5 && ::ActiveRecord::VERSION::MINOR == 1
|
48
48
|
names = @attribute_names
|
49
|
-
method_name_regex = /\A(#{names.join('|'
|
49
|
+
method_name_regex = /\A(#{names.join('|')})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
|
50
50
|
has_attribute = Module.new do
|
51
51
|
define_method :has_attribute? do |attr_name|
|
52
52
|
super(attr_name) || !!method_name_regex.match(attr_name)
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "mobility/util"
|
2
3
|
|
3
4
|
module Mobility
|
@@ -118,7 +119,8 @@ the current locale was +nil+.
|
|
118
119
|
|
119
120
|
=end
|
120
121
|
class Fallbacks < Module
|
121
|
-
# Applies fallbacks plugin to attributes.
|
122
|
+
# Applies fallbacks plugin to attributes. Completely disables fallbacks
|
123
|
+
# on model if option is +false+.
|
122
124
|
# @param [Attributes] attributes
|
123
125
|
# @param [Boolean] option
|
124
126
|
def self.apply(attributes, option)
|
@@ -44,14 +44,14 @@ model class is generated.
|
|
44
44
|
|
45
45
|
# @param [String] One or more attributes
|
46
46
|
def initialize(*attributes)
|
47
|
-
method_name_regex = /\A(#{attributes.join('|'
|
47
|
+
method_name_regex = /\A(#{attributes.join('|')})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
|
48
48
|
|
49
49
|
define_method :method_missing do |method_name, *arguments, **options, &block|
|
50
50
|
if method_name =~ method_name_regex
|
51
51
|
attribute = $1.to_sym
|
52
|
-
locale, suffix = $2.split('_'
|
53
|
-
locale = "#{locale}-#{suffix.upcase}"
|
54
|
-
public_send("#{attribute}#{$4}"
|
52
|
+
locale, suffix = $2.split('_')
|
53
|
+
locale = "#{locale}-#{suffix.upcase}" if suffix
|
54
|
+
public_send("#{attribute}#{$4}", *arguments, **options, locale: locale.to_sym)
|
55
55
|
else
|
56
56
|
super(method_name, *arguments, &block)
|
57
57
|
end
|
@@ -53,7 +53,7 @@ If no locales are passed as an option to the initializer,
|
|
53
53
|
private
|
54
54
|
|
55
55
|
def define_reader(name, locale)
|
56
|
-
warning_message = "locale passed as option to locale accessor will be ignored"
|
56
|
+
warning_message = "locale passed as option to locale accessor will be ignored"
|
57
57
|
normalized_locale = Mobility.normalize_locale(locale)
|
58
58
|
|
59
59
|
define_method "#{name}_#{normalized_locale}" do |**options|
|
@@ -70,7 +70,7 @@ If no locales are passed as an option to the initializer,
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def define_writer(name, locale)
|
73
|
-
warning_message = "locale passed as option to locale accessor will be ignored"
|
73
|
+
warning_message = "locale passed as option to locale accessor will be ignored"
|
74
74
|
normalized_locale = Mobility.normalize_locale(locale)
|
75
75
|
|
76
76
|
define_method "#{name}_#{normalized_locale}=" do |value, **options|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Mobility
|
2
4
|
module Sequel
|
3
5
|
=begin
|
@@ -10,7 +12,7 @@ setter method is called.
|
|
10
12
|
# @param [Array<String>] attributes Backend attributes
|
11
13
|
def initialize(*attributes)
|
12
14
|
attributes.each do |attribute|
|
13
|
-
define_method "#{attribute}="
|
15
|
+
define_method "#{attribute}=" do |value, **options|
|
14
16
|
if !options[:super] && send(attribute) != value
|
15
17
|
locale = options[:locale] || Mobility.locale
|
16
18
|
column = attribute.to_sym
|
data/lib/mobility/translates.rb
CHANGED
data/lib/mobility/util.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Mobility
|
2
4
|
=begin
|
3
5
|
|
@@ -40,7 +42,7 @@ Some useful methods on strings, borrowed in parts from Sequel and ActiveSupport.
|
|
40
42
|
# @return [String]
|
41
43
|
def camelize(str)
|
42
44
|
call_or_yield str do
|
43
|
-
str.to_s.sub(/^[a-z\d]*/) { $&.capitalize }.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub('/'
|
45
|
+
str.to_s.sub(/^[a-z\d]*/) { $&.capitalize }.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub('/', '::')
|
44
46
|
end
|
45
47
|
end
|
46
48
|
|
data/lib/mobility/version.rb
CHANGED
@@ -53,15 +53,15 @@ module Mobility
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def template
|
56
|
-
"#{backend}_translations"
|
56
|
+
"#{backend}_translations"
|
57
57
|
end
|
58
58
|
|
59
59
|
def migration_dir
|
60
|
-
File.expand_path("db/migrate"
|
60
|
+
File.expand_path("db/migrate")
|
61
61
|
end
|
62
62
|
|
63
63
|
def migration_file
|
64
|
-
"create_#{file_name}_#{attributes.map(&:name).join('_and_')}_translations_for_mobility_#{backend}_backend"
|
64
|
+
"create_#{file_name}_#{attributes.map(&:name).join('_and_')}_translations_for_mobility_#{backend}_backend"
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
@@ -1,5 +1,80 @@
|
|
1
1
|
Mobility.configure do |config|
|
2
|
+
# Sets the default backend to use in models. This can be overridden in models
|
3
|
+
# by passing +backend: ...+ to +translates+.
|
2
4
|
config.default_backend = :key_value
|
5
|
+
|
6
|
+
# By default, Mobility uses the +translates+ class method in models to
|
7
|
+
# describe translated attributes, but you can configure this method to be
|
8
|
+
# whatever you like. This may be useful if using Mobility alongside another
|
9
|
+
# translation gem which uses the same method name.
|
3
10
|
config.accessor_method = :translates
|
11
|
+
|
12
|
+
# To query on translated attributes, you need to append a scope to your
|
13
|
+
# model. The name of this scope is +i18n+ by default, but this can be changed
|
14
|
+
# to something else.
|
4
15
|
config.query_method = :i18n
|
16
|
+
|
17
|
+
# Uncomment and remove (or add) items to (from) this list to completely
|
18
|
+
# disable/enable plugins globally (so they cannot be used and are never even
|
19
|
+
# loaded). Note that if you remove an item from the list, you will not be
|
20
|
+
# able to use the plugin at all, and any options for the plugin will be
|
21
|
+
# ignored by models. (In most cases, you probably don't want to change this.)
|
22
|
+
#
|
23
|
+
# config.plugins = %i[
|
24
|
+
# cache
|
25
|
+
# dirty
|
26
|
+
# fallbacks
|
27
|
+
# presence
|
28
|
+
# default
|
29
|
+
# attribute_methods
|
30
|
+
# fallthrough_accessors
|
31
|
+
# locale_accessors
|
32
|
+
# ]
|
33
|
+
|
34
|
+
# The translation cache is on by default, but you can turn it off by
|
35
|
+
# uncommenting this line. (This may be helpful in debugging.)
|
36
|
+
#
|
37
|
+
# config.default_options[:cache] = false
|
38
|
+
|
39
|
+
# Dirty tracking is disabled by default. Uncomment this line to enable it.
|
40
|
+
# If you enable this, you should also enable +locale_accessors+ by default
|
41
|
+
# (see below).
|
42
|
+
#
|
43
|
+
# config.default_options[:dirty] = true
|
44
|
+
|
45
|
+
# No fallbacks are used by default. To define default fallbacks, uncomment
|
46
|
+
# and set the default fallback option value here. A "true" value will use
|
47
|
+
# whatever is defined by +I18n.fallbacks+ (if defined), or alternatively will
|
48
|
+
# fallback to your +I18n.default_locale+.
|
49
|
+
#
|
50
|
+
# config.default_options[:fallbacks] = true
|
51
|
+
|
52
|
+
# The Presence plugin converts empty strings to nil when fetching and setting
|
53
|
+
# translations. By default it is on, uncomment this line to turn it off.
|
54
|
+
#
|
55
|
+
# config.default_options[:presence] = false
|
56
|
+
|
57
|
+
# Set a default value to use if the translation is nil. By default this is
|
58
|
+
# off, uncomment and set a default to use it across all models (you probably
|
59
|
+
# don't want to do that).
|
60
|
+
#
|
61
|
+
# config.default_options[:default] = ...
|
62
|
+
|
63
|
+
# Uncomment to enable locale_accessors by default on models. A true value
|
64
|
+
# will use the locales defined in I18n.available_locales. If you want
|
65
|
+
# something else, pass an array of locales instead.
|
66
|
+
#
|
67
|
+
# config.default_options[:locale_accessors] = true
|
68
|
+
|
69
|
+
# Uncomment to enable fallthrough accessors by default on models. This will
|
70
|
+
# allow you to call any method with a suffix like _en or _pt_br, and Mobility
|
71
|
+
# will catch the suffix and convert it into a locale in +method_missing+. If
|
72
|
+
# you don't need this kind of open-ended fallthrough behavior, it's better
|
73
|
+
# to use locale_accessors instead (which define methods) since method_missing
|
74
|
+
# is very slow. (You can use both fallthrough and locale accessor plugins
|
75
|
+
# together without conflict.)
|
76
|
+
#
|
77
|
+
# Note: The dirty plugin enables fallthrough_accessors by default.
|
78
|
+
#
|
79
|
+
# config.default_options[:fallthrough_accessors] = true
|
5
80
|
end
|
@@ -35,7 +35,7 @@ Other backends are not supported, for obvious reasons:
|
|
35
35
|
=end
|
36
36
|
class TranslationsGenerator < ::Rails::Generators::NamedBase
|
37
37
|
SUPPORTED_BACKENDS = %w[column table]
|
38
|
-
BACKEND_OPTIONS = { type: :string, desc: "Backend to use for translations (defaults to Mobility.default_backend)"
|
38
|
+
BACKEND_OPTIONS = { type: :string, desc: "Backend to use for translations (defaults to Mobility.default_backend)" }
|
39
39
|
argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
|
40
40
|
|
41
41
|
class_option(:backend, BACKEND_OPTIONS)
|
@@ -50,7 +50,7 @@ Other backends are not supported, for obvious reasons:
|
|
50
50
|
def self.prepare_for_invocation(name, value)
|
51
51
|
if name == :backend
|
52
52
|
if SUPPORTED_BACKENDS.include?(value)
|
53
|
-
require_relative "./backend_generators/#{value}_backend"
|
53
|
+
require_relative "./backend_generators/#{value}_backend"
|
54
54
|
Mobility::BackendGenerators.const_get("#{value}_backend".camelcase.freeze)
|
55
55
|
else
|
56
56
|
begin
|
@@ -70,7 +70,7 @@ Other backends are not supported, for obvious reasons:
|
|
70
70
|
|
71
71
|
def say_status(status, message, *args)
|
72
72
|
if status == :invoke && SUPPORTED_BACKENDS.include?(message)
|
73
|
-
super(status, "#{message}_backend"
|
73
|
+
super(status, "#{message}_backend", *args)
|
74
74
|
else
|
75
75
|
super
|
76
76
|
end
|