mobility 0.4.3 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|