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
@@ -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 Backend
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
- module Fallbacks
79
- # @!macro [new] backend_constructor
80
- # @param model Model on which backend is defined
81
- # @param [String] attribute Backend attribute
82
- # @option backend_options [Hash] fallbacks Fallbacks hash
83
- def initialize(model, attributes, **backend_options)
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
- # @!group Backend Accessors
94
- # @!macro backend_reader
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
- attr_reader :fallbacks
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 Backend
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
- # @param [Boolean] presence
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 : value.presence
26
+ value == false ? value : Util.presence(value)
18
27
  end
19
28
 
20
29
  # @group Backend Accessors
21
30
  # @!macro backend_writer
22
- # @param [Boolean] presence
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 : value.presence, **options)
35
+ super(locale, value == false ? value : Util.presence(value), options)
27
36
  end
28
37
  end
29
38
  end
@@ -0,0 +1,6 @@
1
+ module Mobility
2
+ module Plugins
3
+ module Sequel
4
+ end
5
+ end
6
+ 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