mobility 0.8.8 → 1.0.0.alpha
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 +56 -0
- data/Gemfile +52 -16
- data/Gemfile.lock +113 -52
- data/Guardfile +23 -1
- data/README.md +184 -92
- data/Rakefile +6 -4
- data/lib/mobility.rb +40 -166
- data/lib/mobility/active_record/translation.rb +1 -1
- data/lib/mobility/arel/nodes/pg_ops.rb +1 -1
- data/lib/mobility/backend.rb +19 -41
- data/lib/mobility/backends.rb +20 -0
- data/lib/mobility/backends/active_record.rb +4 -0
- data/lib/mobility/backends/active_record/column.rb +2 -0
- data/lib/mobility/backends/active_record/container.rb +4 -2
- data/lib/mobility/backends/active_record/hstore.rb +2 -0
- data/lib/mobility/backends/active_record/json.rb +2 -0
- data/lib/mobility/backends/active_record/jsonb.rb +2 -0
- data/lib/mobility/backends/active_record/key_value.rb +5 -3
- data/lib/mobility/backends/active_record/pg_hash.rb +1 -1
- data/lib/mobility/backends/active_record/serialized.rb +2 -0
- data/lib/mobility/backends/active_record/table.rb +5 -3
- data/lib/mobility/backends/column.rb +0 -6
- data/lib/mobility/backends/container.rb +2 -1
- data/lib/mobility/backends/hash.rb +39 -0
- data/lib/mobility/backends/hstore.rb +0 -1
- data/lib/mobility/backends/json.rb +0 -1
- data/lib/mobility/backends/jsonb.rb +0 -1
- data/lib/mobility/backends/key_value.rb +22 -14
- data/lib/mobility/backends/null.rb +2 -0
- data/lib/mobility/backends/sequel.rb +3 -0
- data/lib/mobility/backends/sequel/column.rb +2 -0
- data/lib/mobility/backends/sequel/container.rb +3 -1
- data/lib/mobility/backends/sequel/hstore.rb +2 -0
- data/lib/mobility/backends/sequel/json.rb +2 -0
- data/lib/mobility/backends/sequel/jsonb.rb +3 -1
- data/lib/mobility/backends/sequel/key_value.rb +8 -6
- data/lib/mobility/backends/sequel/serialized.rb +2 -0
- data/lib/mobility/backends/sequel/table.rb +5 -2
- data/lib/mobility/backends/serialized.rb +1 -3
- data/lib/mobility/backends/table.rb +14 -6
- data/lib/mobility/pluggable.rb +36 -0
- data/lib/mobility/plugin.rb +260 -0
- data/lib/mobility/plugins.rb +26 -25
- data/lib/mobility/plugins/active_model.rb +17 -0
- data/lib/mobility/plugins/active_model/cache.rb +26 -0
- data/lib/mobility/plugins/active_model/dirty.rb +310 -54
- data/lib/mobility/plugins/active_record.rb +34 -0
- data/lib/mobility/plugins/active_record/backend.rb +25 -0
- data/lib/mobility/plugins/active_record/cache.rb +28 -0
- data/lib/mobility/plugins/active_record/dirty.rb +72 -101
- data/lib/mobility/plugins/active_record/query.rb +48 -34
- data/lib/mobility/plugins/active_record/uniqueness_validation.rb +60 -0
- data/lib/mobility/plugins/attribute_methods.rb +28 -20
- data/lib/mobility/plugins/attributes.rb +70 -0
- data/lib/mobility/plugins/backend.rb +138 -0
- data/lib/mobility/plugins/backend_reader.rb +34 -0
- data/lib/mobility/plugins/cache.rb +59 -24
- data/lib/mobility/plugins/default.rb +22 -17
- data/lib/mobility/plugins/dirty.rb +12 -33
- data/lib/mobility/plugins/fallbacks.rb +51 -43
- data/lib/mobility/plugins/fallthrough_accessors.rb +26 -25
- data/lib/mobility/plugins/locale_accessors.rb +25 -35
- data/lib/mobility/plugins/presence.rb +28 -21
- data/lib/mobility/plugins/query.rb +8 -17
- data/lib/mobility/plugins/reader.rb +50 -0
- data/lib/mobility/plugins/sequel.rb +34 -0
- data/lib/mobility/plugins/sequel/backend.rb +25 -0
- data/lib/mobility/plugins/sequel/cache.rb +24 -0
- data/lib/mobility/plugins/sequel/dirty.rb +45 -32
- data/lib/mobility/plugins/sequel/query.rb +21 -6
- data/lib/mobility/plugins/writer.rb +44 -0
- data/lib/mobility/translations.rb +95 -0
- data/lib/mobility/version.rb +12 -1
- data/lib/rails/generators/mobility/templates/initializer.rb +95 -77
- metadata +51 -51
- metadata.gz.sig +0 -0
- data/lib/mobility/active_model.rb +0 -4
- data/lib/mobility/active_model/backend_resetter.rb +0 -26
- data/lib/mobility/active_record.rb +0 -23
- data/lib/mobility/active_record/backend_resetter.rb +0 -26
- data/lib/mobility/active_record/uniqueness_validator.rb +0 -60
- data/lib/mobility/attributes.rb +0 -324
- data/lib/mobility/backend/orm_delegator.rb +0 -44
- data/lib/mobility/backend_resetter.rb +0 -50
- data/lib/mobility/configuration.rb +0 -138
- data/lib/mobility/fallbacks.rb +0 -28
- data/lib/mobility/interface.rb +0 -0
- data/lib/mobility/loaded.rb +0 -4
- data/lib/mobility/plugins/active_record/attribute_methods.rb +0 -38
- data/lib/mobility/plugins/cache/translation_cacher.rb +0 -40
- data/lib/mobility/sequel.rb +0 -9
- data/lib/mobility/sequel/backend_resetter.rb +0 -23
- data/lib/mobility/translates.rb +0 -73
@@ -71,7 +71,7 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
|
|
71
71
|
private
|
72
72
|
|
73
73
|
def get_column_type
|
74
|
-
|
74
|
+
model_class.type_for_attribute(options[:column_name].to_s).try(:type).tap do |type|
|
75
75
|
unless %i[json jsonb].include? type
|
76
76
|
raise InvalidColumnType, "#{options[:column_name]} must be a column of type json or jsonb"
|
77
77
|
end
|
@@ -122,7 +122,7 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
|
|
122
122
|
|
123
123
|
class Coder
|
124
124
|
def self.dump(obj)
|
125
|
-
if obj.is_a? Hash
|
125
|
+
if obj.is_a? ::Hash
|
126
126
|
obj.inject({}) do |translations, (locale, value)|
|
127
127
|
value.each do |k, v|
|
128
128
|
(translations[locale] ||= {})[k] = v if v.present?
|
@@ -141,5 +141,7 @@ Implements the {Mobility::Backends::Container} backend for ActiveRecord models.
|
|
141
141
|
|
142
142
|
class InvalidColumnType < StandardError; end
|
143
143
|
end
|
144
|
+
|
145
|
+
register_backend(:active_record_container, ActiveRecord::Container)
|
144
146
|
end
|
145
147
|
end
|
@@ -39,7 +39,7 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
|
|
39
39
|
options[:association_name] ||= :"#{options[:type]}_translations"
|
40
40
|
options[:class_name] ||= Mobility::ActiveRecord.const_get("#{type.capitalize}Translation")
|
41
41
|
end
|
42
|
-
options[:table_alias_affix] = "#{
|
42
|
+
options[:table_alias_affix] = "#{model_class}_%s_#{options[:association_name]}"
|
43
43
|
rescue NameError
|
44
44
|
raise ArgumentError, "You must define a Mobility::ActiveRecord::#{type.capitalize}Translation class."
|
45
45
|
end
|
@@ -119,7 +119,7 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
|
|
119
119
|
# The title predicate has a non-nil value, so we can use an INNER JOIN,
|
120
120
|
# whereas we are searching for nil content, which requires an OUTER JOIN.
|
121
121
|
#
|
122
|
-
class Visitor < Arel::Visitor
|
122
|
+
class Visitor < ::Mobility::Arel::Visitor
|
123
123
|
private
|
124
124
|
|
125
125
|
def visit_Arel_Nodes_Equality(object)
|
@@ -137,7 +137,7 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
|
|
137
137
|
alias :visit_Array :visit_collection
|
138
138
|
|
139
139
|
def visit_Arel_Nodes_Or(object)
|
140
|
-
[object.left, object.right].map(&method(:visit)).compact.inject(
|
140
|
+
[object.left, object.right].map(&method(:visit)).compact.inject(:merge).
|
141
141
|
transform_values { OUTER_JOIN }
|
142
142
|
end
|
143
143
|
|
@@ -212,5 +212,7 @@ Implements the {Mobility::Backends::KeyValue} backend for ActiveRecord models.
|
|
212
212
|
end
|
213
213
|
end
|
214
214
|
end
|
215
|
+
|
216
|
+
register_backend(:active_record_key_value, ActiveRecord::KeyValue)
|
215
217
|
end
|
216
218
|
end
|
@@ -30,7 +30,7 @@ Internal class used by ActiveRecord backends backed by a Postgres data type
|
|
30
30
|
|
31
31
|
class Coder
|
32
32
|
def self.dump(obj)
|
33
|
-
if obj.is_a? Hash
|
33
|
+
if obj.is_a? ::Hash
|
34
34
|
obj.inject({}) do |translations, (locale, value)|
|
35
35
|
translations[locale] = value if value.present?
|
36
36
|
translations
|
@@ -101,7 +101,7 @@ columns to that table.
|
|
101
101
|
# @option options [Symbol] subclass_name (:Translation) Name of subclass
|
102
102
|
# to append to model class to generate translation class
|
103
103
|
def configure(options)
|
104
|
-
table_name =
|
104
|
+
table_name = model_class.table_name
|
105
105
|
options[:table_name] ||= "#{table_name.singularize}_translations"
|
106
106
|
options[:foreign_key] ||= table_name.downcase.singularize.camelize.foreign_key
|
107
107
|
if (association_name = options[:association_name]).present?
|
@@ -153,7 +153,7 @@ columns to that table.
|
|
153
153
|
def already_joined?(relation, locale, join_type)
|
154
154
|
if join = get_join(relation, locale)
|
155
155
|
return true if (join_type == Visitor::OUTER_JOIN) || (Visitor::INNER_JOIN === join)
|
156
|
-
relation.joins_values
|
156
|
+
relation.joins_values -= [join]
|
157
157
|
end
|
158
158
|
false
|
159
159
|
end
|
@@ -265,7 +265,7 @@ columns to that table.
|
|
265
265
|
touch: true
|
266
266
|
|
267
267
|
before_save do
|
268
|
-
required_attributes = self.class.
|
268
|
+
required_attributes = translation_class.attribute_names.select { |name| self.class.mobility_attribute?(name) }
|
269
269
|
send(association_name).destroy_empty_translations(required_attributes)
|
270
270
|
end
|
271
271
|
|
@@ -304,5 +304,7 @@ columns to that table.
|
|
304
304
|
end
|
305
305
|
end
|
306
306
|
end
|
307
|
+
|
308
|
+
register_backend(:active_record_table, ActiveRecord::Table)
|
307
309
|
end
|
308
310
|
end
|
@@ -27,8 +27,6 @@ be ignored if set, since it would cause a conflict with column accessors.
|
|
27
27
|
|
28
28
|
=end
|
29
29
|
module Column
|
30
|
-
extend Backend::OrmDelegator
|
31
|
-
|
32
30
|
# Returns name of column where translated attribute is stored
|
33
31
|
# @param [Symbol] locale
|
34
32
|
# @return [String]
|
@@ -44,10 +42,6 @@ be ignored if set, since it would cause a conflict with column accessors.
|
|
44
42
|
normalized_locale = Mobility.normalize_locale(locale)
|
45
43
|
"#{attribute}_#{normalized_locale}".to_sym
|
46
44
|
end
|
47
|
-
|
48
|
-
def self.included(base)
|
49
|
-
base.extend Backend::OrmDelegator
|
50
|
-
end
|
51
45
|
end
|
52
46
|
end
|
53
47
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Mobility
|
2
|
+
module Backends
|
3
|
+
=begin
|
4
|
+
|
5
|
+
Backend which stores translations in an in-memory hash.
|
6
|
+
|
7
|
+
=end
|
8
|
+
class Hash
|
9
|
+
include Backend
|
10
|
+
|
11
|
+
# @!group Backend Accessors
|
12
|
+
# @!macro backend_reader
|
13
|
+
# @return [Object]
|
14
|
+
def read(locale, _ = {})
|
15
|
+
translations[locale]
|
16
|
+
end
|
17
|
+
|
18
|
+
# @!macro backend_writer
|
19
|
+
# @return [Object]
|
20
|
+
def write(locale, value, _ = {})
|
21
|
+
translations[locale] = value
|
22
|
+
end
|
23
|
+
# @!endgroup
|
24
|
+
|
25
|
+
# @!macro backend_iterator
|
26
|
+
def each_locale
|
27
|
+
translations.each { |l, _| yield l }
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def translations
|
33
|
+
@translations ||= {}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
register_backend(:hash, Hash)
|
38
|
+
end
|
39
|
+
end
|
@@ -44,8 +44,6 @@ other backends on model (otherwise one will overwrite the other).
|
|
44
44
|
|
45
45
|
=end
|
46
46
|
module KeyValue
|
47
|
-
extend Backend::OrmDelegator
|
48
|
-
|
49
47
|
# @!method association_name
|
50
48
|
# Returns the name of the polymorphic association.
|
51
49
|
# @return [Symbol] Name of the association
|
@@ -87,7 +85,7 @@ other backends on model (otherwise one will overwrite the other).
|
|
87
85
|
module ClassMethods
|
88
86
|
# @!group Backend Configuration
|
89
87
|
# @option options [Symbol,String] type Column type to use
|
90
|
-
# @option options [Symbol]
|
88
|
+
# @option options [Symbol] association_name (:<type>_translations) Name
|
91
89
|
# of association method, defaults to +<type>_translations+
|
92
90
|
# @option options [Symbol] class_name Translation class, defaults to
|
93
91
|
# +Mobility::<ORM>::<type>Translation+
|
@@ -98,20 +96,13 @@ other backends on model (otherwise one will overwrite the other).
|
|
98
96
|
options[:association_name] &&= options[:association_name].to_sym
|
99
97
|
options[:class_name] &&= Util.constantize(options[:class_name])
|
100
98
|
if !(options[:type] || (options[:class_name] && options[:association_name]))
|
101
|
-
|
102
|
-
warn %{
|
103
|
-
WARNING: In previous versions, the Mobility KeyValue backend defaulted to a
|
104
|
-
text type column, but this behavior is now deprecated and will be removed in
|
105
|
-
the next release. Either explicitly specify the type by passing type: :text in
|
106
|
-
each translated model, or set a default option in your configuration.
|
107
|
-
}
|
108
|
-
options[:type] = :text
|
99
|
+
raise ArgumentError, "KeyValue backend requires an explicit type option, either text or string."
|
109
100
|
end
|
110
101
|
end
|
111
102
|
|
112
103
|
# Apply custom processing for plugin
|
113
|
-
# @param (see Backend::
|
114
|
-
# @return (see Backend::
|
104
|
+
# @param (see Backend::ClassMethods#apply_plugin)
|
105
|
+
# @return (see Backend::ClassMethods#apply_plugin)
|
115
106
|
def apply_plugin(name)
|
116
107
|
if name == :cache
|
117
108
|
include self::Cache
|
@@ -127,7 +118,24 @@ each translated model, or set a default option in your configuration.
|
|
127
118
|
end
|
128
119
|
|
129
120
|
module Cache
|
130
|
-
|
121
|
+
def translation_for(locale, **options)
|
122
|
+
return super(locale, options) if options.delete(:cache) == false
|
123
|
+
if cache.has_key?(locale)
|
124
|
+
cache[locale]
|
125
|
+
else
|
126
|
+
cache[locale] = super(locale, options)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def clear_cache
|
131
|
+
@cache = {}
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
|
136
|
+
def cache
|
137
|
+
@cache ||= {}
|
138
|
+
end
|
131
139
|
end
|
132
140
|
end
|
133
141
|
end
|
@@ -44,7 +44,7 @@ Implements the {Mobility::Backends::Container} backend for Sequel models.
|
|
44
44
|
def self.configure(options)
|
45
45
|
options[:column_name] ||= :translations
|
46
46
|
options[:column_name] = options[:column_name].to_sym
|
47
|
-
column_name, db_schema = options[:column_name],
|
47
|
+
column_name, db_schema = options[:column_name], model_class.db_schema
|
48
48
|
options[:column_type] = db_schema[column_name] && (db_schema[column_name][:db_type]).to_sym
|
49
49
|
unless %i[json jsonb].include?(options[:column_type])
|
50
50
|
raise InvalidColumnType, "#{options[:column_name]} must be a column of type json or jsonb"
|
@@ -114,5 +114,7 @@ Implements the {Mobility::Backends::Container} backend for Sequel models.
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
end
|
117
|
+
|
118
|
+
register_backend(:sequel_container, Sequel::Container)
|
117
119
|
end
|
118
120
|
end
|
@@ -55,7 +55,7 @@ Implements the {Mobility::Backends::Jsonb} backend for Sequel models.
|
|
55
55
|
|
56
56
|
def =~(other)
|
57
57
|
case other
|
58
|
-
when Integer, Hash
|
58
|
+
when Integer, ::Hash
|
59
59
|
to_dash_arrow =~ other.to_json
|
60
60
|
when NilClass
|
61
61
|
~to_question
|
@@ -66,5 +66,7 @@ Implements the {Mobility::Backends::Jsonb} backend for Sequel models.
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
69
|
+
|
70
|
+
register_backend(:sequel_jsonb, Sequel::Jsonb)
|
69
71
|
end
|
70
72
|
end
|
@@ -36,7 +36,7 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
|
|
36
36
|
options[:association_name] ||= :"#{options[:type]}_translations"
|
37
37
|
options[:class_name] ||= Mobility::Sequel.const_get("#{type.capitalize}Translation")
|
38
38
|
end
|
39
|
-
options[:table_alias_affix] = "#{
|
39
|
+
options[:table_alias_affix] = "#{model_class}_%s_#{options[:association_name]}"
|
40
40
|
rescue NameError
|
41
41
|
raise ArgumentError, "You must define a Mobility::Sequel::#{type.capitalize}Translation class."
|
42
42
|
end
|
@@ -93,7 +93,7 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
|
|
93
93
|
join_type = nils.empty? ? :inner : :left_outer
|
94
94
|
# TODO: simplify to hash.transform_values { join_type } when
|
95
95
|
# support for Ruby 2.3 is deprecated
|
96
|
-
Hash[hash.keys.map { |key| [key, join_type] }]
|
96
|
+
::Hash[hash.keys.map { |key| [key, join_type] }]
|
97
97
|
else
|
98
98
|
{}
|
99
99
|
end
|
@@ -101,13 +101,13 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
|
|
101
101
|
hash = visit(boolean.args, locale)
|
102
102
|
# TODO: simplify to hash.transform_values { :inner } when
|
103
103
|
# support for Ruby 2.3 is deprecated
|
104
|
-
Hash[hash.keys.map { |key| [key, :inner] }]
|
104
|
+
::Hash[hash.keys.map { |key| [key, :inner] }]
|
105
105
|
elsif boolean.op == :OR
|
106
106
|
hash = boolean.args.map { |op| visit(op, locale) }.
|
107
|
-
compact.inject(
|
107
|
+
compact.inject(:merge)
|
108
108
|
# TODO: simplify to hash.transform_values { :left_outer } when
|
109
109
|
# support for Ruby 2.3 is deprecated
|
110
|
-
Hash[hash.keys.map { |key| [key, :left_outer] }]
|
110
|
+
::Hash[hash.keys.map { |key| [key, :left_outer] }]
|
111
111
|
else
|
112
112
|
visit(boolean.args, locale)
|
113
113
|
end
|
@@ -153,7 +153,7 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
|
|
153
153
|
end
|
154
154
|
define_method :after_save do
|
155
155
|
super()
|
156
|
-
attributes.each { |attribute|
|
156
|
+
attributes.each { |attribute| mobility_backends[attribute].save_translations }
|
157
157
|
end
|
158
158
|
end
|
159
159
|
include callback_methods
|
@@ -202,5 +202,7 @@ Implements the {Mobility::Backends::KeyValue} backend for Sequel models.
|
|
202
202
|
end
|
203
203
|
end
|
204
204
|
end
|
205
|
+
|
206
|
+
register_backend(:sequel_key_value, Sequel::KeyValue)
|
205
207
|
end
|
206
208
|
end
|