mobility 0.1.20 → 0.2.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 +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
|