mobility 0.1.20 → 0.2.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 +2 -0
- data/CHANGELOG.md +17 -0
- data/CONTRIBUTING.md +55 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +2 -56
- data/README.md +64 -15
- data/Rakefile +17 -17
- data/lib/mobility.rb +43 -40
- data/lib/mobility/active_model.rb +0 -1
- data/lib/mobility/active_model/backend_resetter.rb +1 -1
- data/lib/mobility/active_record.rb +8 -15
- data/lib/mobility/active_record/backend_resetter.rb +2 -0
- data/lib/mobility/active_record/model_translation.rb +1 -1
- data/lib/mobility/active_record/string_translation.rb +2 -0
- data/lib/mobility/active_record/text_translation.rb +2 -0
- data/lib/mobility/attributes.rb +74 -71
- data/lib/mobility/backend.rb +64 -25
- data/lib/mobility/backend/orm_delegator.rb +17 -7
- data/lib/mobility/backend/stringify_locale.rb +18 -0
- data/lib/mobility/backend_resetter.rb +8 -5
- data/lib/mobility/backends.rb +4 -0
- data/lib/mobility/backends/active_record.rb +20 -0
- data/lib/mobility/{backend → backends}/active_record/column.rb +25 -13
- data/lib/mobility/{backend → backends}/active_record/column/query_methods.rb +5 -3
- data/lib/mobility/backends/active_record/hstore.rb +29 -0
- data/lib/mobility/{backend → backends}/active_record/hstore/query_methods.rb +2 -2
- data/lib/mobility/{backend → backends}/active_record/jsonb.rb +6 -6
- data/lib/mobility/{backend → backends}/active_record/jsonb/query_methods.rb +4 -2
- data/lib/mobility/{backend → backends}/active_record/key_value.rb +10 -44
- data/lib/mobility/{backend → backends}/active_record/key_value/query_methods.rb +4 -2
- data/lib/mobility/{backend/active_record/hash_valued.rb → backends/active_record/pg_hash.rb} +13 -21
- data/lib/mobility/{backend → backends}/active_record/query_methods.rb +2 -2
- data/lib/mobility/{backend → backends}/active_record/serialized.rb +12 -28
- data/lib/mobility/{backend → backends}/active_record/serialized/query_methods.rb +5 -8
- data/lib/mobility/{backend → backends}/active_record/table.rb +11 -60
- data/lib/mobility/{backend → backends}/active_record/table/query_methods.rb +5 -3
- data/lib/mobility/{backend → backends}/column.rb +8 -4
- data/lib/mobility/backends/hash_valued.rb +29 -0
- data/lib/mobility/{backend → backends}/hstore.rb +4 -4
- data/lib/mobility/{backend → backends}/jsonb.rb +4 -4
- data/lib/mobility/backends/key_value.rb +111 -0
- data/lib/mobility/{backend → backends}/null.rb +4 -4
- data/lib/mobility/backends/sequel.rb +20 -0
- data/lib/mobility/backends/sequel/column.rb +52 -0
- data/lib/mobility/{backend → backends}/sequel/column/query_methods.rb +5 -3
- data/lib/mobility/backends/sequel/hstore.rb +29 -0
- data/lib/mobility/{backend → backends}/sequel/hstore/query_methods.rb +4 -3
- data/lib/mobility/{backend → backends}/sequel/jsonb.rb +6 -6
- data/lib/mobility/{backend → backends}/sequel/jsonb/query_methods.rb +4 -3
- data/lib/mobility/{backend → backends}/sequel/key_value.rb +28 -39
- data/lib/mobility/{backend → backends}/sequel/key_value/query_methods.rb +4 -5
- data/lib/mobility/backends/sequel/pg_hash.rb +46 -0
- data/lib/mobility/{backend → backends}/sequel/postgres_query_methods.rb +1 -2
- data/lib/mobility/{backend → backends}/sequel/query_methods.rb +6 -4
- data/lib/mobility/{backend → backends}/sequel/serialized.rb +17 -38
- data/lib/mobility/backends/sequel/serialized/query_methods.rb +17 -0
- data/lib/mobility/{backend → backends}/sequel/table.rb +29 -60
- data/lib/mobility/{backend → backends}/sequel/table/query_methods.rb +5 -3
- data/lib/mobility/{backend → backends}/serialized.rb +27 -5
- data/lib/mobility/{backend → backends}/table.rb +69 -29
- data/lib/mobility/configuration.rb +40 -0
- data/lib/mobility/{orm.rb → loaded.rb} +0 -0
- data/lib/mobility/plugins.rb +35 -0
- data/lib/mobility/plugins/active_model.rb +6 -0
- data/lib/mobility/plugins/active_model/dirty.rb +81 -0
- data/lib/mobility/plugins/active_record.rb +6 -0
- data/lib/mobility/plugins/active_record/dirty.rb +59 -0
- data/lib/mobility/plugins/cache.rb +54 -0
- data/lib/mobility/plugins/cache/translation_cacher.rb +40 -0
- data/lib/mobility/plugins/default.rb +73 -0
- data/lib/mobility/plugins/dirty.rb +61 -0
- data/lib/mobility/{backend → plugins}/fallbacks.rb +36 -31
- data/lib/mobility/plugins/fallthrough_accessors.rb +66 -0
- data/lib/mobility/plugins/locale_accessors.rb +84 -0
- data/lib/mobility/{backend → plugins}/presence.rb +15 -6
- data/lib/mobility/plugins/sequel.rb +6 -0
- data/lib/mobility/plugins/sequel/dirty.rb +59 -0
- data/lib/mobility/sequel.rb +5 -14
- data/lib/mobility/sequel/backend_resetter.rb +4 -6
- data/lib/mobility/sequel/column_changes.rb +4 -4
- data/lib/mobility/sequel/model_translation.rb +1 -1
- data/lib/mobility/sequel/string_translation.rb +2 -0
- data/lib/mobility/sequel/text_translation.rb +2 -0
- data/lib/mobility/translates.rb +1 -5
- data/lib/mobility/util.rb +126 -0
- data/lib/mobility/version.rb +1 -1
- data/lib/mobility/wrapper.rb +1 -1
- data/lib/rails/generators/mobility/translations_generator.rb +7 -3
- metadata +85 -55
- metadata.gz.sig +0 -0
- data/lib/mobility/backend/active_model.rb +0 -7
- data/lib/mobility/backend/active_model/dirty.rb +0 -95
- data/lib/mobility/backend/active_record.rb +0 -29
- data/lib/mobility/backend/active_record/dirty.rb +0 -54
- data/lib/mobility/backend/active_record/hstore.rb +0 -29
- data/lib/mobility/backend/cache.rb +0 -117
- data/lib/mobility/backend/dirty.rb +0 -38
- data/lib/mobility/backend/key_value.rb +0 -85
- data/lib/mobility/backend/sequel.rb +0 -29
- data/lib/mobility/backend/sequel/column.rb +0 -39
- data/lib/mobility/backend/sequel/dirty.rb +0 -57
- data/lib/mobility/backend/sequel/hash_valued.rb +0 -51
- data/lib/mobility/backend/sequel/hstore.rb +0 -29
- data/lib/mobility/backend/sequel/serialized/query_methods.rb +0 -20
- data/lib/mobility/core_ext/object.rb +0 -30
- data/lib/mobility/core_ext/string.rb +0 -16
- data/lib/mobility/fallthrough_accessors.rb +0 -57
- data/lib/mobility/locale_accessors.rb +0 -55
@@ -1,5 +1,7 @@
|
|
1
|
+
require "mobility/plugins/cache"
|
2
|
+
|
1
3
|
module Mobility
|
2
|
-
module
|
4
|
+
module Backends
|
3
5
|
=begin
|
4
6
|
|
5
7
|
Stores attribute translation as rows on a model-specific translation table
|
@@ -30,14 +32,14 @@ another, and Mobility will handle mapping reads/writes to each. The subclass
|
|
30
32
|
used in this case will be generated from the +association_name+ by
|
31
33
|
singularizing it and converting it to camelcase.
|
32
34
|
|
33
|
-
For more details, see examples in {Mobility::
|
35
|
+
For more details, see examples in {Mobility::Backends::ActiveRecord::Table}.
|
34
36
|
|
35
37
|
==Backend Options
|
36
38
|
|
37
39
|
===+association_name+
|
38
40
|
|
39
|
-
Name of association on model. Defaults to +:
|
40
|
-
|
41
|
+
Name of association on model. Defaults to +:translations+. If specified,
|
42
|
+
ensure name does not overlap with other methods on model or with the
|
41
43
|
association name used by other backends on model (otherwise one will overwrite
|
42
44
|
the other).
|
43
45
|
|
@@ -58,39 +60,77 @@ Subclass to use when dynamically generating translation class for model, by
|
|
58
60
|
default +:Translation+. Should be a symbol. Generally this does not need to be
|
59
61
|
set.
|
60
62
|
|
61
|
-
@see Mobility::
|
62
|
-
@see Mobility::
|
63
|
+
@see Mobility::Backends::ActiveRecord::Table
|
64
|
+
@see Mobility::Backends::Sequel::Table
|
63
65
|
=end
|
64
66
|
module Table
|
65
|
-
|
67
|
+
extend Backend::OrmDelegator
|
68
|
+
|
69
|
+
# @!macro backend_constructor
|
70
|
+
# @option options [Symbol] association_name Name of association
|
71
|
+
def initialize(model, attribute, options = {})
|
72
|
+
super
|
73
|
+
@association_name = options[:association_name]
|
74
|
+
end
|
75
|
+
|
76
|
+
# @!group Backend Accessors
|
77
|
+
# @!macro backend_reader
|
78
|
+
def read(locale, options = {})
|
79
|
+
translation_for(locale, options).send(attribute)
|
80
|
+
end
|
81
|
+
|
82
|
+
# @!macro backend_writer
|
83
|
+
def write(locale, value, options = {})
|
84
|
+
translation_for(locale, options).tap { |t| t.send("#{attribute}=", value) }.send(attribute)
|
85
|
+
end
|
86
|
+
# @!endgroup
|
87
|
+
|
88
|
+
# @!macro backend_iterator
|
89
|
+
def each_locale
|
90
|
+
translations.each { |t| yield t.locale.to_sym }
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def translations
|
96
|
+
model.send(association_name)
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.included(backend)
|
100
|
+
backend.extend ClassMethods
|
101
|
+
end
|
102
|
+
|
103
|
+
module ClassMethods
|
104
|
+
# Apply custom processing for plugin
|
105
|
+
# @param (see Backend::Setup#apply_plugin)
|
106
|
+
# @return (see Backend::Setup#apply_plugin)
|
107
|
+
def apply_plugin(name)
|
108
|
+
if name == :cache
|
109
|
+
include self::Cache
|
110
|
+
true
|
111
|
+
else
|
112
|
+
super
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
66
116
|
|
67
117
|
# Simple hash cache to memoize translations as a hash so they can be
|
68
118
|
# fetched quickly.
|
69
|
-
|
70
|
-
|
71
|
-
# @yield [locale] Yields locale to block in case attribute is not yet
|
72
|
-
# cached, expects a new translation for that locale.
|
73
|
-
# @raise [ArgumentError] if block is not given
|
74
|
-
def initialize
|
75
|
-
raise ArgumentError, "missing block" unless block_given?
|
76
|
-
super() { |hash, locale| hash[locale] = yield(locale) }
|
77
|
-
end
|
119
|
+
module Cache
|
120
|
+
include Plugins::Cache::TranslationCacher.new(:translation_for)
|
78
121
|
|
79
|
-
|
80
|
-
# @param [String] attribute
|
81
|
-
# @return [Class] Hash-like wrapper object to be used as attribute cache
|
82
|
-
def for(attribute)
|
83
|
-
cache = self
|
122
|
+
private
|
84
123
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
124
|
+
def cache
|
125
|
+
model_cache || model.instance_variable_set(:"@__mobility_#{association_name}_cache", {})
|
126
|
+
end
|
89
127
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
128
|
+
def model_cache
|
129
|
+
model.instance_variable_get(:"@__mobility_#{association_name}_cache")
|
130
|
+
end
|
131
|
+
|
132
|
+
def clear_cache
|
133
|
+
model_cache && model_cache.clear
|
94
134
|
end
|
95
135
|
end
|
96
136
|
end
|
@@ -5,6 +5,8 @@ Stores shared Mobility configuration referenced by all backends.
|
|
5
5
|
|
6
6
|
=end
|
7
7
|
class Configuration
|
8
|
+
RESERVED_OPTION_KEYS = %i[backend model_class].freeze
|
9
|
+
|
8
10
|
# Alias for mobility_accessor (defaults to +translates+)
|
9
11
|
# @return [Symbol]
|
10
12
|
attr_accessor :accessor_method
|
@@ -13,6 +15,26 @@ Stores shared Mobility configuration referenced by all backends.
|
|
13
15
|
# @return [Symbol]
|
14
16
|
attr_accessor :query_method
|
15
17
|
|
18
|
+
# Default set of options. These will be merged with any backend options
|
19
|
+
# when defining translated attributes (with +translates+). Default options
|
20
|
+
# may not include the keys 'backend' or 'model_class'.
|
21
|
+
# @return [Hash]
|
22
|
+
attr_reader :default_options
|
23
|
+
def default_options=(options)
|
24
|
+
if (keys = options.keys & RESERVED_OPTION_KEYS).present?
|
25
|
+
raise ReservedOptionKey,
|
26
|
+
"Default options may not contain the following reserved keys: #{keys.join(', ')}"
|
27
|
+
else
|
28
|
+
@default_options = options
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Plugins to apply. Order of plugins is important, as this becomes the
|
33
|
+
# order in which plugins modules are included into the backend class or
|
34
|
+
# attributes instance.
|
35
|
+
# @return [Array<Symbol>]
|
36
|
+
attr_accessor :plugins
|
37
|
+
|
16
38
|
# Default fallbacks instance
|
17
39
|
# @return [I18n::Locale::Fallbacks]
|
18
40
|
def default_fallbacks(fallbacks = {})
|
@@ -41,6 +63,24 @@ Stores shared Mobility configuration referenced by all backends.
|
|
41
63
|
@query_method = :i18n
|
42
64
|
@default_fallbacks = lambda { |fallbacks| I18n::Locale::Fallbacks.new(fallbacks) }
|
43
65
|
@default_accessor_locales = lambda { I18n.available_locales }
|
66
|
+
@default_options = {
|
67
|
+
cache: true,
|
68
|
+
dirty: false,
|
69
|
+
fallbacks: nil,
|
70
|
+
presence: true,
|
71
|
+
default: nil
|
72
|
+
}
|
73
|
+
@plugins = %i[
|
74
|
+
cache
|
75
|
+
dirty
|
76
|
+
fallbacks
|
77
|
+
presence
|
78
|
+
default
|
79
|
+
fallthrough_accessors
|
80
|
+
locale_accessors
|
81
|
+
]
|
44
82
|
end
|
83
|
+
|
84
|
+
class ReservedOptionKey < Exception; end
|
45
85
|
end
|
46
86
|
end
|
File without changes
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Mobility
|
2
|
+
=begin
|
3
|
+
|
4
|
+
Plugins allow modular customization of backends independent of the backend
|
5
|
+
itself. They are enabled through the {Configuration.plugins} configuration
|
6
|
+
setting, which takes an array of symbols corresponding to plugin names. The
|
7
|
+
order of these names is important since it determines the order in which
|
8
|
+
plugins will be applied.
|
9
|
+
|
10
|
+
So if our {Configuration.plugins} is an array +[:foo]+, and we call
|
11
|
+
`translates` on our model, +Post+, like this:
|
12
|
+
|
13
|
+
class Post
|
14
|
+
translates :title, foo: true
|
15
|
+
end
|
16
|
+
|
17
|
+
Then the +Foo+ plugin will be applied with the option value +true+. Applying a
|
18
|
+
module calls a class method, +apply+ (in this case +Foo.apply+), which takes
|
19
|
+
two arguments:
|
20
|
+
|
21
|
+
- an instance of the {Attributes} class, +attributes+, from which the backend
|
22
|
+
can configure the backend class (+attributes.backend_class+) and the model
|
23
|
+
(+attributes.model_class+), and the +attributes+ module itself (which
|
24
|
+
will be included into the backend).
|
25
|
+
- the value of the +option+ passed into the model with +translates+ (in this
|
26
|
+
case, +true+).
|
27
|
+
|
28
|
+
Typically, the plugin will include a module into either
|
29
|
+
+attributes.backend_class+ or +attributes+ itself, configured according to the
|
30
|
+
option value. For examples, see classes under the {Mobility::Plugins} namespace.
|
31
|
+
|
32
|
+
=end
|
33
|
+
module Plugins
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Mobility
|
4
|
+
module Plugins
|
5
|
+
=begin
|
6
|
+
|
7
|
+
Dirty tracking for models which include the +ActiveModel::Dirty+ module.
|
8
|
+
|
9
|
+
Assuming we have an attribute +title+, this module will add support for the
|
10
|
+
following methods:
|
11
|
+
- +title_changed?+
|
12
|
+
- +title_change+
|
13
|
+
- +title_was+
|
14
|
+
- +title_will_change!+
|
15
|
+
- +title_previously_changed?+
|
16
|
+
- +title_previous_change+
|
17
|
+
- +restore_title!+
|
18
|
+
|
19
|
+
In addition, the private method +restore_attribute!+ will also restore the
|
20
|
+
value of the translated attribute if passed to it.
|
21
|
+
|
22
|
+
@see http://api.rubyonrails.org/classes/ActiveModel/Dirty.html Rails documentation for Active Model Dirty module
|
23
|
+
|
24
|
+
=end
|
25
|
+
module ActiveModel
|
26
|
+
module Dirty
|
27
|
+
# @!group Backend Accessors
|
28
|
+
# @!macro backend_writer
|
29
|
+
# @param [Hash] options
|
30
|
+
def write(locale, value, options = {})
|
31
|
+
locale_accessor = Mobility.normalize_locale_accessor(attribute, locale)
|
32
|
+
if model.changed_attributes.has_key?(locale_accessor) && model.changed_attributes[locale_accessor] == value
|
33
|
+
model.attributes_changed_by_setter.except!(locale_accessor)
|
34
|
+
elsif read(locale, options.merge(fallback: false)) != value
|
35
|
+
model.send(:attribute_will_change!, locale_accessor)
|
36
|
+
end
|
37
|
+
super
|
38
|
+
end
|
39
|
+
# @!endgroup
|
40
|
+
|
41
|
+
# Builds module which adds suffix/prefix methods for translated
|
42
|
+
# attributes so they act like normal dirty-tracked attributes.
|
43
|
+
class MethodsBuilder < Module
|
44
|
+
def initialize(*attribute_names)
|
45
|
+
attribute_names.each do |name|
|
46
|
+
method_suffixes.each do |suffix|
|
47
|
+
define_method "#{name}#{suffix}".freeze do
|
48
|
+
__send__("attribute#{suffix}".freeze, Mobility.normalize_locale_accessor(name))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
define_method "restore_#{name}!".freeze do
|
53
|
+
locale_accessor = Mobility.normalize_locale_accessor(name)
|
54
|
+
if attribute_changed?(locale_accessor)
|
55
|
+
__send__("#{name}=".freeze, changed_attributes[locale_accessor])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
define_method :restore_attribute! do |attr|
|
61
|
+
attribute_names.include?(attr.to_s) ? send("restore_#{attr}!".freeze) : super(attr)
|
62
|
+
end
|
63
|
+
private :restore_attribute!
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# Get method suffixes. Creating an object just to get the list of
|
69
|
+
# suffixes is not very efficient, but the most reliable way given that
|
70
|
+
# they change from Rails version to version.
|
71
|
+
def method_suffixes
|
72
|
+
@method_suffixes ||=
|
73
|
+
Class.new do
|
74
|
+
include ::ActiveModel::Dirty
|
75
|
+
end.attribute_method_matchers.map(&:suffix).select { |m| m =~ /\A_/ }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
require "mobility/plugins/active_model/dirty"
|
3
|
+
|
4
|
+
module Mobility
|
5
|
+
module Plugins
|
6
|
+
=begin
|
7
|
+
|
8
|
+
Dirty tracking for AR models. See {Mobility::Plugins::ActiveModel::Dirty} for
|
9
|
+
details on usage.
|
10
|
+
|
11
|
+
=end
|
12
|
+
module ActiveRecord
|
13
|
+
module Dirty
|
14
|
+
include ActiveModel::Dirty
|
15
|
+
|
16
|
+
# Builds module which patches a few AR methods to handle changes to
|
17
|
+
# translated attributes just like normal attributes.
|
18
|
+
class MethodsBuilder < ActiveModel::Dirty::MethodsBuilder
|
19
|
+
def initialize(*attribute_names)
|
20
|
+
super
|
21
|
+
@attribute_names = attribute_names
|
22
|
+
|
23
|
+
changes_applied_method = ::ActiveRecord::VERSION::STRING < '5.1' ? :changes_applied : :changes_internally_applied
|
24
|
+
define_method changes_applied_method do
|
25
|
+
@previously_changed = changes
|
26
|
+
super()
|
27
|
+
end
|
28
|
+
|
29
|
+
define_method :clear_changes_information do
|
30
|
+
@previously_changed = ActiveSupport::HashWithIndifferentAccess.new
|
31
|
+
super()
|
32
|
+
end
|
33
|
+
|
34
|
+
define_method :previous_changes do
|
35
|
+
(@previously_changed ||= ActiveSupport::HashWithIndifferentAccess.new).merge(super())
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Overrides +ActiveRecord::AttributeMethods::ClassMethods#has_attribute+ to treat fallthrough attribute methods
|
40
|
+
# just like "real" attribute methods.
|
41
|
+
#
|
42
|
+
# @note Patching +has_attribute?+ is necessary as of AR 5.1 due to this commit[https://github.com/rails/rails/commit/4fed08fa787a316fa51f14baca9eae11913f5050].
|
43
|
+
# (I have voiced my opposition to this change here[https://github.com/rails/rails/pull/27963#issuecomment-310092787]).
|
44
|
+
# @param [Attributes] attributes
|
45
|
+
def included(model_class)
|
46
|
+
names = @attribute_names
|
47
|
+
method_name_regex = /\A(#{names.join('|'.freeze)})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
|
48
|
+
has_attribute = Module.new do
|
49
|
+
define_method :has_attribute? do |attr_name|
|
50
|
+
super(attr_name) || !!method_name_regex.match(attr_name)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
model_class.extend has_attribute
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "mobility/plugins/cache/translation_cacher"
|
2
|
+
|
3
|
+
module Mobility
|
4
|
+
module Plugins
|
5
|
+
=begin
|
6
|
+
|
7
|
+
Caches values fetched from the backend so subsequent fetches can be performed
|
8
|
+
more quickly. The cache stores cached values in a simple hash, which is not
|
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.
|
12
|
+
|
13
|
+
The cache is reset when one of a set of events happens (saving, reloading,
|
14
|
+
etc.). See {BackendResetter} for details.
|
15
|
+
|
16
|
+
Values are added to the cache in two ways:
|
17
|
+
|
18
|
+
1. first read from backend
|
19
|
+
2. any write to backend
|
20
|
+
|
21
|
+
=end
|
22
|
+
module Cache
|
23
|
+
# Applies cache plugin to attributes.
|
24
|
+
# @param [Attributes] attributes
|
25
|
+
# @param [Boolean] option
|
26
|
+
def self.apply(attributes, option)
|
27
|
+
if option
|
28
|
+
backend_class = attributes.backend_class
|
29
|
+
backend_class.include(self) unless backend_class.apply_plugin(:cache)
|
30
|
+
|
31
|
+
model_class = attributes.model_class
|
32
|
+
model_class.include BackendResetter.for(model_class).new(attributes.names) { clear_cache }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# @group Backend Accessors
|
37
|
+
#
|
38
|
+
# @!macro backend_reader
|
39
|
+
# @option options [Boolean] cache
|
40
|
+
# *false* to disable cache.
|
41
|
+
# @!method read(locale, value, options = {})
|
42
|
+
include TranslationCacher.new(:read)
|
43
|
+
|
44
|
+
# @!macro backend_writer
|
45
|
+
# @option options [Boolean] cache
|
46
|
+
# *false* to disable cache.
|
47
|
+
def write(locale, value, **options)
|
48
|
+
return super if options.delete(:cache) == false
|
49
|
+
cache[locale] = super
|
50
|
+
end
|
51
|
+
# @!endgroup
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Mobility
|
2
|
+
module Plugins
|
3
|
+
module Cache
|
4
|
+
=begin
|
5
|
+
|
6
|
+
Creates a module to cache a given translation fetch method. The cacher defines
|
7
|
+
private methods +cache+ and +clear_cache+ to access and clear, respectively, a
|
8
|
+
translations hash.
|
9
|
+
|
10
|
+
This cacher is used to cache translation values in {Mobility::Plugins::Cache},
|
11
|
+
and also to cache translation *records* in {Mobility::Backends::Table} and
|
12
|
+
{Mobility::Backends::KeyValue}.
|
13
|
+
|
14
|
+
=end
|
15
|
+
class TranslationCacher < Module
|
16
|
+
# @param [Symbol] fetch_method Name of translation fetch method to cache
|
17
|
+
def initialize(fetch_method)
|
18
|
+
define_method fetch_method do |locale, **options|
|
19
|
+
return super(locale, options) if options.delete(:cache) == false
|
20
|
+
if cache.has_key?(locale)
|
21
|
+
cache[locale]
|
22
|
+
else
|
23
|
+
cache[locale] = super(locale, options)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
define_method :cache do
|
28
|
+
@cache ||= {}
|
29
|
+
end
|
30
|
+
|
31
|
+
define_method :clear_cache do
|
32
|
+
@cache = {}
|
33
|
+
end
|
34
|
+
|
35
|
+
private :cache, :clear_cache
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|