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
@@ -0,0 +1,73 @@
|
|
1
|
+
module Mobility
|
2
|
+
module Plugins
|
3
|
+
=begin
|
4
|
+
|
5
|
+
Defines value or proc to fall through to if return value from getter would
|
6
|
+
otherwise be nil.
|
7
|
+
|
8
|
+
@example With default enabled (falls through to default value)
|
9
|
+
class Post
|
10
|
+
extend Mobility
|
11
|
+
translates :title, default: 'foo'
|
12
|
+
end
|
13
|
+
|
14
|
+
Mobility.locale = :en
|
15
|
+
post = Post.new(title: "English title")
|
16
|
+
|
17
|
+
Mobility.locale = :de
|
18
|
+
post.title
|
19
|
+
#=> 'foo'
|
20
|
+
|
21
|
+
@example Overriding default with reader option
|
22
|
+
class Post
|
23
|
+
extend Mobility
|
24
|
+
translates :title, default: 'foo'
|
25
|
+
end
|
26
|
+
|
27
|
+
Mobility.locale = :en
|
28
|
+
post = Post.new(title: "English title")
|
29
|
+
|
30
|
+
Mobility.locale = :de
|
31
|
+
post.title
|
32
|
+
#=> 'foo'
|
33
|
+
|
34
|
+
post.title(default: 'bar')
|
35
|
+
#=> 'bar'
|
36
|
+
|
37
|
+
post.title(default: nil)
|
38
|
+
#=> nil
|
39
|
+
|
40
|
+
@example Using Proc as default
|
41
|
+
class Post
|
42
|
+
extend Mobility
|
43
|
+
translates :title, default: lambda { |model:, attribute:| attribute.to_s }
|
44
|
+
end
|
45
|
+
|
46
|
+
post = Post.new(title: nil)
|
47
|
+
post.title
|
48
|
+
#=> "title"
|
49
|
+
|
50
|
+
post.title(default: lambda { |model:| model.class.name.to_s })
|
51
|
+
#=> "Post"
|
52
|
+
=end
|
53
|
+
class Default < Module
|
54
|
+
# Applies default plugin to attributes.
|
55
|
+
# @param [Attributes] attributes
|
56
|
+
# @param [Object] option
|
57
|
+
def self.apply(attributes, option)
|
58
|
+
attributes.backend_class.include(new(option))
|
59
|
+
end
|
60
|
+
|
61
|
+
def initialize(default_option)
|
62
|
+
define_method :read do |locale, options = {}|
|
63
|
+
default = options.has_key?(:default) ? options.delete(:default) : default_option
|
64
|
+
if (value = super(locale, options)).nil?
|
65
|
+
default.is_a?(Proc) ? default.call(model: model, attribute: attribute) : default
|
66
|
+
else
|
67
|
+
value
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "mobility/backend_resetter"
|
2
|
+
require "mobility/plugins/fallthrough_accessors"
|
3
|
+
|
4
|
+
module Mobility
|
5
|
+
module Plugins
|
6
|
+
=begin
|
7
|
+
|
8
|
+
Dirty tracking for Mobility attributes. See class-specific implementations for
|
9
|
+
details.
|
10
|
+
|
11
|
+
@see Mobility::Plugins::ActiveModel::Dirty
|
12
|
+
@see Mobility::Plugins::Sequel::Dirty
|
13
|
+
|
14
|
+
@note Dirty tracking can have unexpected results when combined with fallbacks.
|
15
|
+
A change in the fallback locale value will not mark an attribute falling
|
16
|
+
through to that locale as changed, even though it may look like it has
|
17
|
+
changed. However, when the value for the current locale is changed from nil
|
18
|
+
or blank to a new value, the change will be recorded as a change from that
|
19
|
+
fallback value, rather than from the nil or blank value. The specs are the
|
20
|
+
most reliable source of information on the interaction between dirty tracking
|
21
|
+
and fallbacks.
|
22
|
+
|
23
|
+
=end
|
24
|
+
module Dirty
|
25
|
+
class << self
|
26
|
+
# Applies dirty plugin to attributes for a given option value.
|
27
|
+
# @param [Attributes] attributes
|
28
|
+
# @param [Boolean] option Value of option
|
29
|
+
# @raise [ArgumentError] if model class does not support dirty tracking
|
30
|
+
def apply(attributes, option)
|
31
|
+
if option
|
32
|
+
FallthroughAccessors.apply(attributes, true)
|
33
|
+
include_dirty_module(attributes.backend_class, attributes.model_class, *attributes.names)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def include_dirty_module(backend_class, model_class, *attribute_names)
|
40
|
+
dirty_module =
|
41
|
+
if Loaded::ActiveRecord && model_class.ancestors.include?(::ActiveModel::Dirty)
|
42
|
+
if (model_class < ::ActiveRecord::Base)
|
43
|
+
require "mobility/plugins/active_record/dirty"
|
44
|
+
Plugins::ActiveRecord::Dirty
|
45
|
+
else
|
46
|
+
require "mobility/plugins/active_model/dirty"
|
47
|
+
Plugins::ActiveModel::Dirty
|
48
|
+
end
|
49
|
+
elsif Loaded::Sequel && model_class < ::Sequel::Model
|
50
|
+
require "mobility/plugins/sequel/dirty"
|
51
|
+
Plugins::Sequel::Dirty
|
52
|
+
else
|
53
|
+
raise ArgumentError, "#{model_class} does not support Dirty module."
|
54
|
+
end
|
55
|
+
backend_class.include dirty_module
|
56
|
+
model_class.include dirty_module.const_get(:MethodsBuilder).new(*attribute_names)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
|
+
require "mobility/util"
|
2
|
+
|
1
3
|
module Mobility
|
2
|
-
module
|
4
|
+
module Plugins
|
3
5
|
=begin
|
4
6
|
|
5
7
|
Falls back to one or more alternative locales in case no value is defined for a
|
@@ -75,41 +77,44 @@ locale was +nil+.
|
|
75
77
|
post.title(fallback: :fr)
|
76
78
|
#=> "Mobilité"
|
77
79
|
=end
|
78
|
-
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
|
83
|
-
|
84
|
-
super
|
85
|
-
@fallbacks =
|
86
|
-
if (fallbacks = backend_options[:fallbacks]).is_a?(Hash)
|
87
|
-
Mobility.default_fallbacks(fallbacks)
|
88
|
-
elsif fallbacks == true
|
89
|
-
Mobility.default_fallbacks
|
90
|
-
end
|
80
|
+
class Fallbacks < Module
|
81
|
+
# Applies fallbacks plugin to attributes.
|
82
|
+
# @param [Attributes] attributes
|
83
|
+
# @param [Boolean] option
|
84
|
+
def self.apply(attributes, option)
|
85
|
+
attributes.backend_class.include(new(option)) unless option == false
|
91
86
|
end
|
92
87
|
|
93
|
-
|
94
|
-
|
95
|
-
# @param [Boolean,Symbol,Array] fallback
|
96
|
-
# +false+ to disable fallbacks on lookup, or a locale or array of
|
97
|
-
# locales to set fallback(s) for this lookup.
|
98
|
-
def read(locale, **options)
|
99
|
-
if !options[:fallbacks].nil?
|
100
|
-
warn "You passed an option with key 'fallbacks', which will be
|
101
|
-
ignored. Did you mean 'fallback'?"
|
102
|
-
end
|
103
|
-
fallback = options.delete(:fallback)
|
104
|
-
return super if fallback == false || (fallback.nil? && fallbacks.nil?)
|
105
|
-
(fallback ? [locale, *fallback] : fallbacks[locale]).detect do |fallback_locale|
|
106
|
-
value = super(fallback_locale, **options)
|
107
|
-
break value if value.present?
|
108
|
-
end
|
88
|
+
def initialize(fallbacks_option)
|
89
|
+
define_read(convert_option_to_fallbacks(fallbacks_option))
|
109
90
|
end
|
110
91
|
|
111
92
|
private
|
112
|
-
|
93
|
+
|
94
|
+
def define_read(fallbacks)
|
95
|
+
define_method :read do |locale, **options|
|
96
|
+
fallback = options.delete(:fallback)
|
97
|
+
|
98
|
+
if fallback == false || (fallback.nil? && fallbacks.nil?)
|
99
|
+
super(locale, options)
|
100
|
+
else
|
101
|
+
(fallback ? [locale, *fallback] : fallbacks[locale]).detect do |fallback_locale|
|
102
|
+
value = super(fallback_locale, options)
|
103
|
+
break value if Util.present?(value)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def convert_option_to_fallbacks(option)
|
110
|
+
if option.is_a?(Hash)
|
111
|
+
Mobility.default_fallbacks(option)
|
112
|
+
elsif option == true
|
113
|
+
Mobility.default_fallbacks
|
114
|
+
else
|
115
|
+
option
|
116
|
+
end
|
117
|
+
end
|
113
118
|
end
|
114
119
|
end
|
115
120
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Mobility
|
4
|
+
module Plugins
|
5
|
+
=begin
|
6
|
+
|
7
|
+
Defines +method_missing+ and +respond_to_missing?+ methods for a set of
|
8
|
+
attributes such that a method call using a locale accessor, like:
|
9
|
+
|
10
|
+
article.title_pt_br
|
11
|
+
|
12
|
+
will return the value of +article.title+ with the locale set to +pt-BR+ around
|
13
|
+
the method call. The class is called "FallthroughAccessors" because when
|
14
|
+
included in a model class, locale-specific methods will be available even if
|
15
|
+
not explicitly defined with the +locale_accessors+ option.
|
16
|
+
|
17
|
+
This is a less efficient (but more open-ended) implementation of locale
|
18
|
+
accessors, for use in cases where the locales to be used are not known when the
|
19
|
+
model class is generated.
|
20
|
+
|
21
|
+
@example Using fallthrough locales on a plain old ruby class
|
22
|
+
class Post
|
23
|
+
def title
|
24
|
+
"title in #{Mobility.locale}"
|
25
|
+
end
|
26
|
+
include Mobility::FallthroughAccessors.new("title")
|
27
|
+
end
|
28
|
+
|
29
|
+
Mobility.locale = :en
|
30
|
+
post = Post.new
|
31
|
+
post.title
|
32
|
+
#=> "title in en"
|
33
|
+
post.title_fr
|
34
|
+
#=> "title in fr"
|
35
|
+
|
36
|
+
=end
|
37
|
+
class FallthroughAccessors < Module
|
38
|
+
# Apply fallthrough accessors plugin to attributes.
|
39
|
+
# @param [Attributes] attributes
|
40
|
+
# @param [Boolean] option
|
41
|
+
def self.apply(attributes, option)
|
42
|
+
attributes.model_class.include new(*attributes.names) if option
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param [String] One or more attributes
|
46
|
+
def initialize(*attributes)
|
47
|
+
method_name_regex = /\A(#{attributes.join('|'.freeze)})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
|
48
|
+
|
49
|
+
define_method :method_missing do |method_name, *arguments, &block|
|
50
|
+
if method_name =~ method_name_regex
|
51
|
+
attribute = $1.to_sym
|
52
|
+
locale, suffix = $2.split('_'.freeze)
|
53
|
+
locale = "#{locale}-#{suffix.upcase}".freeze if suffix
|
54
|
+
Mobility.with_locale(locale) { public_send("#{attribute}#{$4}".freeze, *arguments) }
|
55
|
+
else
|
56
|
+
super(method_name, *arguments, &block)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
define_method :respond_to_missing? do |method_name, include_private = false|
|
61
|
+
(method_name =~ method_name_regex) || super(method_name, include_private)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Mobility
|
4
|
+
module Plugins
|
5
|
+
=begin
|
6
|
+
|
7
|
+
Defines methods for a set of locales to access translated attributes in those
|
8
|
+
locales directly with a method call, using a suffix including the locale:
|
9
|
+
|
10
|
+
article.title_pt_br
|
11
|
+
|
12
|
+
If no locales are passed as an option to the initializer,
|
13
|
+
+I18n.available_locales+ will be used by default.
|
14
|
+
|
15
|
+
@example
|
16
|
+
class Post
|
17
|
+
def title
|
18
|
+
"title in #{Mobility.locale}"
|
19
|
+
end
|
20
|
+
include Mobility::Plugins::LocaleAccessors.new("title", locales: [:en, :fr])
|
21
|
+
end
|
22
|
+
|
23
|
+
Mobility.locale = :en
|
24
|
+
post = Post.new
|
25
|
+
post.title
|
26
|
+
#=> "title in en"
|
27
|
+
post.title_fr
|
28
|
+
#=> "title in fr"
|
29
|
+
|
30
|
+
=end
|
31
|
+
class LocaleAccessors < Module
|
32
|
+
# Apply locale accessors plugin to attributes.
|
33
|
+
# @param [Attributes] attributes
|
34
|
+
# @param [Boolean] option
|
35
|
+
def self.apply(attributes, option)
|
36
|
+
if accessor_locales = option
|
37
|
+
accessor_locales = Mobility.config.default_accessor_locales if accessor_locales == true
|
38
|
+
attributes.model_class.include new(*attributes.names, locales: accessor_locales)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param [String] One or more attribute names
|
43
|
+
# @param [Array<Symbol>] Locales
|
44
|
+
def initialize(*attribute_names, locales: I18n.available_locales)
|
45
|
+
attribute_names.each do |name|
|
46
|
+
locales.each do |locale|
|
47
|
+
define_reader(name, locale)
|
48
|
+
define_writer(name, locale)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def define_reader(name, locale)
|
56
|
+
warning_message = "locale passed as option to locale accessor will be ignored".freeze
|
57
|
+
normalized_locale = Mobility.normalize_locale(locale)
|
58
|
+
|
59
|
+
define_method "#{name}_#{normalized_locale}" do |**options|
|
60
|
+
return super() if options.delete(:super)
|
61
|
+
warn warning_message if options.delete(:locale)
|
62
|
+
Mobility.with_locale(locale) { send(name, options) }
|
63
|
+
end
|
64
|
+
|
65
|
+
define_method "#{name}_#{normalized_locale}?" do |**options|
|
66
|
+
return super() if options.delete(:super)
|
67
|
+
warn warning_message if options.delete(:locale)
|
68
|
+
Mobility.with_locale(locale) { send("#{name}?", options) }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def define_writer(name, locale)
|
73
|
+
warning_message = "locale passed as option to locale accessor will be ignored".freeze
|
74
|
+
normalized_locale = Mobility.normalize_locale(locale)
|
75
|
+
|
76
|
+
define_method "#{name}_#{normalized_locale}=" do |value, **options|
|
77
|
+
return super(value) if options.delete(:super)
|
78
|
+
warn warning_message if options.delete(:locale)
|
79
|
+
Mobility.with_locale(locale) { send("#{name}=", value, options) }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -1,29 +1,38 @@
|
|
1
|
+
require "mobility/util"
|
2
|
+
|
1
3
|
module Mobility
|
2
|
-
module
|
4
|
+
module Plugins
|
3
5
|
=begin
|
4
6
|
|
5
7
|
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.
|
8
|
+
backend. Included by default, but can be disabled with +presence: false+ option.
|
7
9
|
|
8
10
|
=end
|
9
11
|
module Presence
|
12
|
+
# Applies presence plugin to attributes.
|
13
|
+
# @param [Attributes] attributes
|
14
|
+
# @param [Boolean] option
|
15
|
+
def self.apply(attributes, option)
|
16
|
+
attributes.backend_class.include(self) if option
|
17
|
+
end
|
18
|
+
|
10
19
|
# @group Backend Accessors
|
11
20
|
# @!macro backend_reader
|
12
|
-
# @
|
21
|
+
# @option options [Boolean] presence
|
13
22
|
# *false* to disable presence filter.
|
14
23
|
def read(locale, **options)
|
15
24
|
return super if options.delete(:presence) == false
|
16
25
|
value = super
|
17
|
-
value == false ? value :
|
26
|
+
value == false ? value : Util.presence(value)
|
18
27
|
end
|
19
28
|
|
20
29
|
# @group Backend Accessors
|
21
30
|
# @!macro backend_writer
|
22
|
-
# @
|
31
|
+
# @option options [Boolean] presence
|
23
32
|
# *false* to disable presence filter.
|
24
33
|
def write(locale, value, **options)
|
25
34
|
return super if options.delete(:presence) == false
|
26
|
-
super(locale, value == false ? value :
|
35
|
+
super(locale, value == false ? value : Util.presence(value), options)
|
27
36
|
end
|
28
37
|
end
|
29
38
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
require "sequel/plugins/dirty"
|
3
|
+
|
4
|
+
module Mobility
|
5
|
+
module Plugins
|
6
|
+
=begin
|
7
|
+
|
8
|
+
Dirty tracking for Sequel models which use the +Sequel::Plugins::Dirty+ plugin.
|
9
|
+
Automatically includes dirty plugin in model class when enabled.
|
10
|
+
|
11
|
+
@see http://sequel.jeremyevans.net/rdoc-plugins/index.html Sequel dirty plugin
|
12
|
+
|
13
|
+
=end
|
14
|
+
module Sequel
|
15
|
+
module Dirty
|
16
|
+
# @!group Backend Accessors
|
17
|
+
# @!macro backend_writer
|
18
|
+
# @param [Hash] options
|
19
|
+
def write(locale, value, options = {})
|
20
|
+
locale_accessor = Mobility.normalize_locale_accessor(attribute, locale).to_sym
|
21
|
+
if model.column_changes.has_key?(locale_accessor) && model.initial_values[locale_accessor] == value
|
22
|
+
super
|
23
|
+
[model.changed_columns, model.initial_values].each { |h| h.delete(locale_accessor) }
|
24
|
+
elsif read(locale, options.merge(fallback: false)) != value
|
25
|
+
model.will_change_column(locale_accessor)
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
# @!endgroup
|
30
|
+
|
31
|
+
# Builds module which overrides dirty methods to handle translated as
|
32
|
+
# well as normal (untranslated) attributes.
|
33
|
+
class MethodsBuilder < Module
|
34
|
+
def initialize(*attribute_names)
|
35
|
+
# Although we load the plugin in the included callback method, we
|
36
|
+
# need to include this module here in advance to ensure that its
|
37
|
+
# instance methods are included *before* the ones defined here.
|
38
|
+
include ::Sequel::Plugins::Dirty::InstanceMethods
|
39
|
+
|
40
|
+
%w[initial_value column_change column_changed? reset_column].each do |method_name|
|
41
|
+
define_method method_name do |column|
|
42
|
+
if attribute_names.map(&:to_sym).include?(column)
|
43
|
+
super(Mobility.normalize_locale_accessor(column).to_sym)
|
44
|
+
else
|
45
|
+
super(column)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def included(model_class)
|
52
|
+
# this just adds Sequel::Plugins::Dirty to @plugins
|
53
|
+
model_class.plugin :dirty
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|