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.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -0
  4. data/CHANGELOG.md +17 -0
  5. data/CONTRIBUTING.md +55 -0
  6. data/Gemfile +2 -0
  7. data/Gemfile.lock +2 -56
  8. data/README.md +64 -15
  9. data/Rakefile +17 -17
  10. data/lib/mobility.rb +43 -40
  11. data/lib/mobility/active_model.rb +0 -1
  12. data/lib/mobility/active_model/backend_resetter.rb +1 -1
  13. data/lib/mobility/active_record.rb +8 -15
  14. data/lib/mobility/active_record/backend_resetter.rb +2 -0
  15. data/lib/mobility/active_record/model_translation.rb +1 -1
  16. data/lib/mobility/active_record/string_translation.rb +2 -0
  17. data/lib/mobility/active_record/text_translation.rb +2 -0
  18. data/lib/mobility/attributes.rb +74 -71
  19. data/lib/mobility/backend.rb +64 -25
  20. data/lib/mobility/backend/orm_delegator.rb +17 -7
  21. data/lib/mobility/backend/stringify_locale.rb +18 -0
  22. data/lib/mobility/backend_resetter.rb +8 -5
  23. data/lib/mobility/backends.rb +4 -0
  24. data/lib/mobility/backends/active_record.rb +20 -0
  25. data/lib/mobility/{backend → backends}/active_record/column.rb +25 -13
  26. data/lib/mobility/{backend → backends}/active_record/column/query_methods.rb +5 -3
  27. data/lib/mobility/backends/active_record/hstore.rb +29 -0
  28. data/lib/mobility/{backend → backends}/active_record/hstore/query_methods.rb +2 -2
  29. data/lib/mobility/{backend → backends}/active_record/jsonb.rb +6 -6
  30. data/lib/mobility/{backend → backends}/active_record/jsonb/query_methods.rb +4 -2
  31. data/lib/mobility/{backend → backends}/active_record/key_value.rb +10 -44
  32. data/lib/mobility/{backend → backends}/active_record/key_value/query_methods.rb +4 -2
  33. data/lib/mobility/{backend/active_record/hash_valued.rb → backends/active_record/pg_hash.rb} +13 -21
  34. data/lib/mobility/{backend → backends}/active_record/query_methods.rb +2 -2
  35. data/lib/mobility/{backend → backends}/active_record/serialized.rb +12 -28
  36. data/lib/mobility/{backend → backends}/active_record/serialized/query_methods.rb +5 -8
  37. data/lib/mobility/{backend → backends}/active_record/table.rb +11 -60
  38. data/lib/mobility/{backend → backends}/active_record/table/query_methods.rb +5 -3
  39. data/lib/mobility/{backend → backends}/column.rb +8 -4
  40. data/lib/mobility/backends/hash_valued.rb +29 -0
  41. data/lib/mobility/{backend → backends}/hstore.rb +4 -4
  42. data/lib/mobility/{backend → backends}/jsonb.rb +4 -4
  43. data/lib/mobility/backends/key_value.rb +111 -0
  44. data/lib/mobility/{backend → backends}/null.rb +4 -4
  45. data/lib/mobility/backends/sequel.rb +20 -0
  46. data/lib/mobility/backends/sequel/column.rb +52 -0
  47. data/lib/mobility/{backend → backends}/sequel/column/query_methods.rb +5 -3
  48. data/lib/mobility/backends/sequel/hstore.rb +29 -0
  49. data/lib/mobility/{backend → backends}/sequel/hstore/query_methods.rb +4 -3
  50. data/lib/mobility/{backend → backends}/sequel/jsonb.rb +6 -6
  51. data/lib/mobility/{backend → backends}/sequel/jsonb/query_methods.rb +4 -3
  52. data/lib/mobility/{backend → backends}/sequel/key_value.rb +28 -39
  53. data/lib/mobility/{backend → backends}/sequel/key_value/query_methods.rb +4 -5
  54. data/lib/mobility/backends/sequel/pg_hash.rb +46 -0
  55. data/lib/mobility/{backend → backends}/sequel/postgres_query_methods.rb +1 -2
  56. data/lib/mobility/{backend → backends}/sequel/query_methods.rb +6 -4
  57. data/lib/mobility/{backend → backends}/sequel/serialized.rb +17 -38
  58. data/lib/mobility/backends/sequel/serialized/query_methods.rb +17 -0
  59. data/lib/mobility/{backend → backends}/sequel/table.rb +29 -60
  60. data/lib/mobility/{backend → backends}/sequel/table/query_methods.rb +5 -3
  61. data/lib/mobility/{backend → backends}/serialized.rb +27 -5
  62. data/lib/mobility/{backend → backends}/table.rb +69 -29
  63. data/lib/mobility/configuration.rb +40 -0
  64. data/lib/mobility/{orm.rb → loaded.rb} +0 -0
  65. data/lib/mobility/plugins.rb +35 -0
  66. data/lib/mobility/plugins/active_model.rb +6 -0
  67. data/lib/mobility/plugins/active_model/dirty.rb +81 -0
  68. data/lib/mobility/plugins/active_record.rb +6 -0
  69. data/lib/mobility/plugins/active_record/dirty.rb +59 -0
  70. data/lib/mobility/plugins/cache.rb +54 -0
  71. data/lib/mobility/plugins/cache/translation_cacher.rb +40 -0
  72. data/lib/mobility/plugins/default.rb +73 -0
  73. data/lib/mobility/plugins/dirty.rb +61 -0
  74. data/lib/mobility/{backend → plugins}/fallbacks.rb +36 -31
  75. data/lib/mobility/plugins/fallthrough_accessors.rb +66 -0
  76. data/lib/mobility/plugins/locale_accessors.rb +84 -0
  77. data/lib/mobility/{backend → plugins}/presence.rb +15 -6
  78. data/lib/mobility/plugins/sequel.rb +6 -0
  79. data/lib/mobility/plugins/sequel/dirty.rb +59 -0
  80. data/lib/mobility/sequel.rb +5 -14
  81. data/lib/mobility/sequel/backend_resetter.rb +4 -6
  82. data/lib/mobility/sequel/column_changes.rb +4 -4
  83. data/lib/mobility/sequel/model_translation.rb +1 -1
  84. data/lib/mobility/sequel/string_translation.rb +2 -0
  85. data/lib/mobility/sequel/text_translation.rb +2 -0
  86. data/lib/mobility/translates.rb +1 -5
  87. data/lib/mobility/util.rb +126 -0
  88. data/lib/mobility/version.rb +1 -1
  89. data/lib/mobility/wrapper.rb +1 -1
  90. data/lib/rails/generators/mobility/translations_generator.rb +7 -3
  91. metadata +85 -55
  92. metadata.gz.sig +0 -0
  93. data/lib/mobility/backend/active_model.rb +0 -7
  94. data/lib/mobility/backend/active_model/dirty.rb +0 -95
  95. data/lib/mobility/backend/active_record.rb +0 -29
  96. data/lib/mobility/backend/active_record/dirty.rb +0 -54
  97. data/lib/mobility/backend/active_record/hstore.rb +0 -29
  98. data/lib/mobility/backend/cache.rb +0 -117
  99. data/lib/mobility/backend/dirty.rb +0 -38
  100. data/lib/mobility/backend/key_value.rb +0 -85
  101. data/lib/mobility/backend/sequel.rb +0 -29
  102. data/lib/mobility/backend/sequel/column.rb +0 -39
  103. data/lib/mobility/backend/sequel/dirty.rb +0 -57
  104. data/lib/mobility/backend/sequel/hash_valued.rb +0 -51
  105. data/lib/mobility/backend/sequel/hstore.rb +0 -29
  106. data/lib/mobility/backend/sequel/serialized/query_methods.rb +0 -20
  107. data/lib/mobility/core_ext/object.rb +0 -30
  108. data/lib/mobility/core_ext/string.rb +0 -16
  109. data/lib/mobility/fallthrough_accessors.rb +0 -57
  110. data/lib/mobility/locale_accessors.rb +0 -55
@@ -1,7 +1,9 @@
1
+ require "mobility/backends/sequel/query_methods"
2
+
1
3
  module Mobility
2
- module Backend
4
+ module Backends
3
5
  class Sequel::KeyValue::QueryMethods < Sequel::QueryMethods
4
- def initialize(attributes, association_name: nil, class_name: nil, **_)
6
+ def initialize(attributes, association_name: nil, class_name: nil, **)
5
7
  super
6
8
 
7
9
  define_join_method(association_name, class_name)
@@ -34,9 +36,6 @@ module Mobility
34
36
  end
35
37
 
36
38
  def define_query_methods(association_name)
37
- # TODO: find a better way to do this that doesn't involve overriding
38
- # a private method...
39
- #
40
39
  attributes_extractor = @attributes_extractor
41
40
 
42
41
  %w[exclude or where].each do |method_name|
@@ -0,0 +1,46 @@
1
+ require "mobility/util"
2
+ require "mobility/backends/sequel"
3
+ require "mobility/backends/hash_valued"
4
+ require "mobility/backend/stringify_locale"
5
+
6
+ module Mobility
7
+ module Backends
8
+ =begin
9
+
10
+ Internal class used by Sequel backends backed by a Postgres data type (hstore,
11
+ jsonb).
12
+
13
+ =end
14
+ class Sequel::PgHash
15
+ include Sequel
16
+ include HashValued
17
+ include StringifyLocale
18
+
19
+ # @!macro backend_iterator
20
+ def each_locale
21
+ super { |l| yield l.to_sym }
22
+ end
23
+
24
+ def translations
25
+ model[attribute.to_sym]
26
+ end
27
+
28
+ setup do |attributes|
29
+ method_overrides = Module.new do
30
+ define_method :initialize_set do |values|
31
+ attributes.each { |attribute| self[attribute.to_sym] = {} }
32
+ super(values)
33
+ end
34
+ define_method :before_validation do
35
+ attributes.each do |attribute|
36
+ self[attribute.to_sym].delete_if { |_, v| Util.blank?(v) }
37
+ end
38
+ super()
39
+ end
40
+ end
41
+ include method_overrides
42
+ include Mobility::Sequel::ColumnChanges.new(attributes)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,6 +1,5 @@
1
-
2
1
  module Mobility
3
- module Backend
2
+ module Backends
4
3
  module PostgresQueryMethods
5
4
  private
6
5
 
@@ -1,5 +1,7 @@
1
+ require "mobility/util"
2
+
1
3
  module Mobility
2
- module Backend
4
+ module Backends
3
5
  module Sequel
4
6
  =begin
5
7
 
@@ -9,10 +11,10 @@ models. For details see backend-specific subclasses.
9
11
  =end
10
12
  class QueryMethods < Module
11
13
  # @param [Array<String>] attributes Translated attributes
12
- def initialize(attributes, **_)
13
- @attributes = attributes.map! &:to_sym
14
+ def initialize(attributes, _)
15
+ @attributes = attributes.map!(&:to_sym)
14
16
  @attributes_extractor = lambda do |cond|
15
- cond.is_a?(Hash) && (cond.keys & attributes).presence
17
+ cond.is_a?(Hash) && Util.presence(cond.keys & attributes)
16
18
  end
17
19
  end
18
20
  end
@@ -1,8 +1,12 @@
1
+ require "mobility/backends/sequel"
2
+ require "mobility/backends/hash_valued"
3
+ require "mobility/backends/serialized"
4
+
1
5
  module Mobility
2
- module Backend
6
+ module Backends
3
7
  =begin
4
8
 
5
- Implements {Mobility::Backend::Serialized} backend for Sequel models, using the
9
+ Implements {Mobility::Backends::Serialized} backend for Sequel models, using the
6
10
  Sequel serialization plugin.
7
11
 
8
12
  @see http://sequel.jeremyevans.net/rdoc-plugins/classes/Sequel/Plugins/Serialization.html Sequel serialization plugin
@@ -10,7 +14,7 @@ Sequel serialization plugin.
10
14
 
11
15
  @example Define attribute with serialized backend
12
16
  class Post < Sequel::Model
13
- include Mobility
17
+ extend Mobility
14
18
  translates :title, backend: :serialized, format: :yaml
15
19
  end
16
20
 
@@ -23,35 +27,22 @@ Sequel serialization plugin.
23
27
  post.save
24
28
  post.deserialized_values[:title] # get deserialized value
25
29
  #=> {:en=>"foo", :ja=>"あああ"}
26
- post.title_before_mobility # get serialized value
30
+ post.title(super: true) # get serialized value
27
31
  #=> "---\n:en: foo\n:ja: \"あああ\"\n"
28
32
 
29
33
  =end
30
34
  class Sequel::Serialized
31
35
  include Sequel
36
+ include HashValued
32
37
 
33
- require 'mobility/backend/sequel/serialized/query_methods'
34
-
35
- # @!group Backend Accessors
36
- #
37
- # @!macro backend_reader
38
- def read(locale, **_)
39
- translations[locale]
40
- end
41
-
42
- # @!macro backend_reader
43
- def write(locale, value, **_)
44
- translations[locale] = value
45
- end
46
- # @!endgroup
38
+ require 'mobility/backends/sequel/serialized/query_methods'
47
39
 
48
40
  # @!group Backend Configuration
49
- # @option options [Symbol] format (:yaml) Serialization format
50
- # @raise [ArgumentError] if a format other than +:yaml+ or +:json+ is passed in
41
+ # @param (see Backends::Serialized.configure)
42
+ # @option (see Backends::Serialized.configure)
43
+ # @raise (see Backends::Serialized.configure)
51
44
  def self.configure(options)
52
- options[:format] ||= :yaml
53
- options[:format] = options[:format].downcase.to_sym
54
- raise ArgumentError, "Serialized backend only supports yaml or json formats." unless [:yaml, :json].include?(options[:format])
45
+ Serialized.configure(options)
55
46
  end
56
47
  # @!endgroup
57
48
 
@@ -68,7 +59,7 @@ Sequel serialization plugin.
68
59
 
69
60
  method_overrides = Module.new do
70
61
  define_method :initialize_set do |values|
71
- attributes.each { |attribute| send(:"#{attribute}_before_mobility=", {}.send(:"to_#{format}")) }
62
+ attributes.each { |attribute| self[attribute.to_sym] = {}.send(:"to_#{format}") }
72
63
  super(values)
73
64
  end
74
65
  end
@@ -92,24 +83,12 @@ Sequel serialization plugin.
92
83
  end
93
84
  end
94
85
 
95
- # @!group Cache Methods
96
- # @return [Hash]
97
- def new_cache
98
- translations
99
- end
100
-
101
- # @return [Boolean]
102
- def write_to_cache?
103
- true
104
- end
105
- # @!endgroup
106
-
107
86
  # @note The original serialization_modification_detection plugin sets
108
87
  # +@original_deserialized_values+ to be +@deserialized_values+, which
109
88
  # doesn't work. Setting it to a new empty hash seems to work better.
110
89
  module SerializationModificationDetectionFix
111
90
  def after_save
112
- super()
91
+ super
113
92
  @original_deserialized_values = {}
114
93
  end
115
94
  end
@@ -121,7 +100,7 @@ Sequel serialization plugin.
121
100
  end
122
101
 
123
102
  def serialized_value
124
- model.send("#{attribute}_before_mobility")
103
+ model[attribute.to_sym]
125
104
  end
126
105
  end
127
106
  end
@@ -0,0 +1,17 @@
1
+ require "mobility/backends/sequel/query_methods"
2
+
3
+ module Mobility
4
+ module Backends
5
+ class Sequel::Serialized::QueryMethods < Sequel::QueryMethods
6
+ def initialize(attributes, _)
7
+ super
8
+ attributes_extractor = @attributes_extractor
9
+ cond_checker = Backends::Serialized.attr_checker(attributes_extractor)
10
+
11
+ define_method :where do |*cond, &block|
12
+ cond_checker.call(cond.first) || super(*cond, &block)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,14 +1,21 @@
1
+ require "mobility/util"
2
+ require "mobility/backends/sequel"
3
+ require "mobility/backends/key_value"
4
+ require "mobility/sequel/model_translation"
5
+
1
6
  module Mobility
2
- module Backend
7
+ module Backends
3
8
  =begin
4
9
 
5
- Implements the {Mobility::Backend::Table} backend for Sequel models.
10
+ Implements the {Mobility::Backends::Table} backend for Sequel models.
6
11
 
7
12
  =end
8
13
  class Sequel::Table
9
14
  include Sequel
15
+ include Table
16
+ include Util
10
17
 
11
- require 'mobility/backend/sequel/table/query_methods'
18
+ require 'mobility/backends/sequel/table/query_methods'
12
19
 
13
20
  # @return [Symbol] name of the association method
14
21
  attr_reader :association_name
@@ -17,26 +24,13 @@ Implements the {Mobility::Backend::Table} backend for Sequel models.
17
24
  attr_reader :translation_class
18
25
 
19
26
  # @!macro backend_constructor
20
- # @option options [Symbol] association_name Name of association
21
- def initialize(model, attribute, **options)
27
+ def initialize(model, attribute, options = {})
22
28
  super
23
- @association_name = options[:association_name]
24
29
  @translation_class = options[:model_class].const_get(options[:subclass_name])
25
30
  end
26
31
 
27
- # @!group Backend Accessors
28
- # @!macro backend_reader
29
- def read(locale, **_)
30
- translation_for(locale).send(attribute)
31
- end
32
-
33
- # @!macro backend_reader
34
- def write(locale, value, **_)
35
- translation_for(locale).tap { |t| t.send("#{attribute}=", value) }.send(attribute)
36
- end
37
-
38
32
  # @!group Backend Configuration
39
- # @option options [Symbol] association_name (:mobility_model_translations) Name of association method
33
+ # @option options [Symbol] association_name (:translations) Name of association method
40
34
  # @option options [Symbol] table_name Name of translation table
41
35
  # @option options [Symbol] foreign_key Name of foreign key
42
36
  # @option options [Symbol] subclass_name Name of subclass to append to model class to generate translation class
@@ -44,12 +38,12 @@ Implements the {Mobility::Backend::Table} backend for Sequel models.
44
38
  def self.configure(options)
45
39
  raise CacheRequired, "Cache required for Sequel::Table backend" if options[:cache] == false
46
40
  table_name = options[:model_class].table_name
47
- options[:table_name] ||= :"#{table_name.to_s.singularize}_translations"
48
- options[:foreign_key] ||= table_name.to_s.downcase.singularize.camelize.foreign_key
49
- if (association_name = options[:association_name]).present?
50
- options[:subclass_name] ||= association_name.to_s.singularize.camelize
41
+ options[:table_name] ||= :"#{singularize(table_name)}_translations"
42
+ options[:foreign_key] ||= foreign_key(camelize(singularize(table_name.to_s.downcase)))
43
+ if association_name = options[:association_name]
44
+ options[:subclass_name] ||= camelize(singularize(association_name))
51
45
  else
52
- options[:association_name] = :mobility_model_translations
46
+ options[:association_name] = :translations
53
47
  options[:subclass_name] ||= :Translation
54
48
  end
55
49
  %i[table_name foreign_key association_name subclass_name].each { |key| options[key] = options[key].to_sym }
@@ -60,10 +54,6 @@ Implements the {Mobility::Backend::Table} backend for Sequel models.
60
54
  association_name = options[:association_name]
61
55
  subclass_name = options[:subclass_name]
62
56
 
63
- cache_accessor_name = :"__#{association_name}_cache"
64
-
65
- attr_accessor cache_accessor_name
66
-
67
57
  translation_class =
68
58
  if self.const_defined?(subclass_name, false)
69
59
  const_get(subclass_name, false)
@@ -88,9 +78,10 @@ Implements the {Mobility::Backend::Table} backend for Sequel models.
88
78
  callback_methods = Module.new do
89
79
  define_method :after_save do
90
80
  super()
91
- send(cache_accessor_name).each_value do |translation|
92
- translation.id ? translation.save : send("add_#{association_name.to_s.singularize}", translation)
93
- end if send(cache_accessor_name)
81
+ cache_accessor = instance_variable_get(:"@__mobility_#{association_name}_cache")
82
+ cache_accessor.each_value do |translation|
83
+ translation.id ? translation.save : send("add_#{Util.singularize(association_name)}", translation)
84
+ end if cache_accessor
94
85
  end
95
86
  end
96
87
  include callback_methods
@@ -100,42 +91,20 @@ Implements the {Mobility::Backend::Table} backend for Sequel models.
100
91
 
101
92
  setup_query_methods(QueryMethods)
102
93
 
103
- # @!group Cache Methods
104
- # @return [Table::TranslationsCache]
105
- def new_cache
106
- reset_model_cache unless model_cache
107
- model_cache.for(attribute)
108
- end
109
-
110
- # @return [Boolean]
111
- def write_to_cache?
112
- true
113
- end
114
-
115
- def clear_cache
116
- model_cache.clear if model_cache
117
- end
118
- # @!endgroup
119
-
120
- private
121
-
122
- def translation_for(locale)
123
- translation = translations.find { |t| t.locale == locale.to_s }
94
+ def translation_for(locale, _)
95
+ translation = model.send(association_name).find { |t| t.locale == locale.to_s }
124
96
  translation ||= translation_class.new(locale: locale)
125
97
  translation
126
98
  end
127
99
 
128
- def translations
129
- model.send(association_name)
130
- end
100
+ module Cache
101
+ include Table::Cache
131
102
 
132
- def model_cache
133
- model.send(:"__#{association_name}_cache")
134
- end
103
+ private
135
104
 
136
- def reset_model_cache
137
- model.send(:"__#{association_name}_cache=",
138
- Table::TranslationsCache.new { |locale| translation_for(locale) })
105
+ def translations
106
+ (model.send(association_name) + cache.values).uniq
107
+ end
139
108
  end
140
109
 
141
110
  class CacheRequired < ::StandardError; end
@@ -1,5 +1,7 @@
1
+ require "mobility/backends/sequel/query_methods"
2
+
1
3
  module Mobility
2
- module Backend
4
+ module Backends
3
5
  class Sequel::Table::QueryMethods < Sequel::QueryMethods
4
6
  def initialize(attributes, association_name: nil, model_class: nil, subclass_name: nil, **options)
5
7
  super
@@ -15,7 +17,7 @@ module Mobility
15
17
  end
16
18
  end
17
19
 
18
- def define_join_method(association_name, translation_class, table_name: nil, foreign_key: nil, **_)
20
+ def define_join_method(association_name, translation_class, table_name: nil, foreign_key: nil, **)
19
21
  define_method :"join_#{association_name}" do |**options|
20
22
  return self if (@__mobility_table_joined || []).include?(table_name)
21
23
  (@__mobility_table_joined ||= []) << table_name
@@ -29,7 +31,7 @@ module Mobility
29
31
  end
30
32
  end
31
33
 
32
- def define_query_methods(association_name, translation_class, **_)
34
+ def define_query_methods(association_name, translation_class, **)
33
35
  attributes_extractor = @attributes_extractor
34
36
 
35
37
  # See note in AR Table QueryMethods class about limitations of
@@ -1,5 +1,7 @@
1
+ require "mobility/util"
2
+
1
3
  module Mobility
2
- module Backend
4
+ module Backends
3
5
  =begin
4
6
 
5
7
  Stores translations as serialized attributes in a single text column. This
@@ -15,20 +17,31 @@ with the same name as the translated attribute.
15
17
 
16
18
  Format for serialization. Either +:yaml+ (default) or +:json+.
17
19
 
18
- @see Mobility::Backend::ActiveRecord::Serialized
19
- @see Mobility::Backend::Sequel::Serialized
20
+ @see Mobility::Backends::ActiveRecord::Serialized
21
+ @see Mobility::Backends::Sequel::Serialized
20
22
 
21
23
  =end
22
24
  module Serialized
23
- include OrmDelegator
25
+ extend Backend::OrmDelegator
24
26
 
25
27
  class << self
28
+
29
+ # @!group Backend Configuration
30
+ # @option options [Symbol] format (:yaml) Serialization format
31
+ # @raise [ArgumentError] if a format other than +:yaml+ or +:json+ is passed in
32
+ def configure(options)
33
+ options[:format] ||= :yaml
34
+ options[:format] = options[:format].downcase.to_sym
35
+ raise ArgumentError, "Serialized backend only supports yaml or json formats." unless [:yaml, :json].include?(options[:format])
36
+ end
37
+ # @!endgroup
38
+
26
39
  def serializer_for(format)
27
40
  lambda do |obj|
28
41
  return if obj.nil?
29
42
  if obj.is_a? Hash
30
43
  obj = obj.inject({}) do |translations, (locale, value)|
31
- translations[locale] = value.to_s if value.present?
44
+ translations[locale] = value.to_s if Util.present?(value)
32
45
  translations
33
46
  end
34
47
  else
@@ -47,6 +60,15 @@ Format for serialization. Either +:yaml+ (default) or +:json+.
47
60
  lambda { |v| JSON.parse(v, symbolize_names: true) }
48
61
  end
49
62
  end
63
+
64
+ def attr_checker(attributes_extractor)
65
+ lambda do |cond|
66
+ if keys = attributes_extractor.call(cond)
67
+ raise ArgumentError,
68
+ "You cannot query on mobility attributes translated with the Serialized backend (#{keys.join(", ")})."
69
+ end
70
+ end
71
+ end
50
72
  end
51
73
  end
52
74
  end